gofmt no coding standards
This commit is contained in:
parent
8bbf879cb3
commit
9571a51286
@ -21,3 +21,8 @@ Command line options
|
|||||||
|
|
||||||
-c launch the developer console
|
-c launch the developer console
|
||||||
-m start mining fake blocks and broadcast fake messages to the net
|
-m start mining fake blocks and broadcast fake messages to the net
|
||||||
|
|
||||||
|
Contribution
|
||||||
|
============
|
||||||
|
|
||||||
|
See CONTRIB.md
|
||||||
|
106
block_manager.go
106
block_manager.go
@ -1,90 +1,90 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ethereum/ethutil-go"
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlockChain struct {
|
type BlockChain struct {
|
||||||
lastBlock *ethutil.Block
|
lastBlock *ethutil.Block
|
||||||
|
|
||||||
genesisBlock *ethutil.Block
|
genesisBlock *ethutil.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockChain() *BlockChain {
|
func NewBlockChain() *BlockChain {
|
||||||
bc := &BlockChain{}
|
bc := &BlockChain{}
|
||||||
bc.genesisBlock = ethutil.NewBlock( ethutil.Encode(ethutil.Genesis) )
|
bc.genesisBlock = ethutil.NewBlock(ethutil.Encode(ethutil.Genesis))
|
||||||
|
|
||||||
return bc
|
return bc
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockManager struct {
|
type BlockManager struct {
|
||||||
vm *Vm
|
vm *Vm
|
||||||
|
|
||||||
blockChain *BlockChain
|
blockChain *BlockChain
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockManager() *BlockManager {
|
func NewBlockManager() *BlockManager {
|
||||||
bm := &BlockManager{vm: NewVm()}
|
bm := &BlockManager{vm: NewVm()}
|
||||||
|
|
||||||
return bm
|
return bm
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process a block.
|
// Process a block.
|
||||||
func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error {
|
func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error {
|
||||||
// TODO Validation (Or move to other part of the application)
|
// TODO Validation (Or move to other part of the application)
|
||||||
if err := bm.ValidateBlock(block); err != nil {
|
if err := bm.ValidateBlock(block); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tx count. Used to create enough channels to 'join' the go routines
|
// Get the tx count. Used to create enough channels to 'join' the go routines
|
||||||
txCount := len(block.Transactions())
|
txCount := len(block.Transactions())
|
||||||
// Locking channel. When it has been fully buffered this method will return
|
// Locking channel. When it has been fully buffered this method will return
|
||||||
lockChan := make(chan bool, txCount)
|
lockChan := make(chan bool, txCount)
|
||||||
|
|
||||||
// Process each transaction/contract
|
// Process each transaction/contract
|
||||||
for _, tx := range block.Transactions() {
|
for _, tx := range block.Transactions() {
|
||||||
// If there's no recipient, it's a contract
|
// If there's no recipient, it's a contract
|
||||||
if tx.IsContract() {
|
if tx.IsContract() {
|
||||||
go bm.ProcessContract(tx, block, lockChan)
|
go bm.ProcessContract(tx, block, lockChan)
|
||||||
} else {
|
} else {
|
||||||
// "finish" tx which isn't a contract
|
// "finish" tx which isn't a contract
|
||||||
lockChan <- true
|
lockChan <- true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all Tx to finish processing
|
// Wait for all Tx to finish processing
|
||||||
for i := 0; i < txCount; i++ {
|
for i := 0; i < txCount; i++ {
|
||||||
<- lockChan
|
<-lockChan
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bm *BlockManager) ValidateBlock(block *ethutil.Block) error {
|
func (bm *BlockManager) ValidateBlock(block *ethutil.Block) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil.Block, lockChan chan bool) {
|
func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil.Block, lockChan chan bool) {
|
||||||
// Recovering function in case the VM had any errors
|
// Recovering function in case the VM had any errors
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
fmt.Println("Recovered from VM execution with err =", r)
|
fmt.Println("Recovered from VM execution with err =", r)
|
||||||
// Let the channel know where done even though it failed (so the execution may resume normally)
|
// Let the channel know where done even though it failed (so the execution may resume normally)
|
||||||
lockChan <- true
|
lockChan <- true
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Process contract
|
// Process contract
|
||||||
bm.vm.ProcContract(tx, block, func(opType OpType) bool {
|
bm.vm.ProcContract(tx, block, func(opType OpType) bool {
|
||||||
// TODO turn on once big ints are in place
|
// TODO turn on once big ints are in place
|
||||||
//if !block.PayFee(tx.Hash(), StepFee.Uint64()) {
|
//if !block.PayFee(tx.Hash(), StepFee.Uint64()) {
|
||||||
// return false
|
// return false
|
||||||
//}
|
//}
|
||||||
|
|
||||||
return true // Continue
|
return true // Continue
|
||||||
})
|
})
|
||||||
|
|
||||||
// Broadcast we're done
|
// Broadcast we're done
|
||||||
lockChan <- true
|
lockChan <- true
|
||||||
}
|
}
|
||||||
|
187
dagger.go
187
dagger.go
@ -1,142 +1,145 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"github.com/ethereum/ethutil-go"
|
||||||
"math/rand"
|
"github.com/obscuren/sha3"
|
||||||
"time"
|
"hash"
|
||||||
"github.com/obscuren/sha3"
|
"math/big"
|
||||||
"hash"
|
"math/rand"
|
||||||
"github.com/ethereum/ethutil-go"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Dagger struct {
|
type Dagger struct {
|
||||||
hash *big.Int
|
hash *big.Int
|
||||||
xn *big.Int
|
xn *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
var Found bool
|
var Found bool
|
||||||
|
|
||||||
func (dag *Dagger) Find(obj *big.Int, resChan chan int64) {
|
func (dag *Dagger) Find(obj *big.Int, resChan chan int64) {
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
rnd := r.Int63()
|
rnd := r.Int63()
|
||||||
|
|
||||||
if dag.Eval(big.NewInt(rnd)).Cmp(obj) < 0 {
|
if dag.Eval(big.NewInt(rnd)).Cmp(obj) < 0 {
|
||||||
// Post back result on the channel
|
// Post back result on the channel
|
||||||
resChan <- rnd
|
resChan <- rnd
|
||||||
// Notify other threads we've found a valid nonce
|
// Notify other threads we've found a valid nonce
|
||||||
Found = true
|
Found = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Break out if found
|
// Break out if found
|
||||||
if Found { break }
|
if Found {
|
||||||
}
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resChan <- 0
|
resChan <- 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
|
func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
|
||||||
// TODO fix multi threading. Somehow it results in the wrong nonce
|
// TODO fix multi threading. Somehow it results in the wrong nonce
|
||||||
amountOfRoutines := 1
|
amountOfRoutines := 1
|
||||||
|
|
||||||
dag.hash = hash
|
dag.hash = hash
|
||||||
|
|
||||||
obj := ethutil.BigPow(2, 256)
|
obj := ethutil.BigPow(2, 256)
|
||||||
obj = obj.Div(obj, diff)
|
obj = obj.Div(obj, diff)
|
||||||
|
|
||||||
Found = false
|
Found = false
|
||||||
resChan := make(chan int64, 3)
|
resChan := make(chan int64, 3)
|
||||||
var res int64
|
var res int64
|
||||||
|
|
||||||
for k := 0; k < amountOfRoutines; k++ {
|
for k := 0; k < amountOfRoutines; k++ {
|
||||||
go dag.Find(obj, resChan)
|
go dag.Find(obj, resChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for each go routine to finish
|
// Wait for each go routine to finish
|
||||||
for k := 0; k < amountOfRoutines; k++ {
|
for k := 0; k < amountOfRoutines; k++ {
|
||||||
// Get the result from the channel. 0 = quit
|
// Get the result from the channel. 0 = quit
|
||||||
if r := <- resChan; r != 0 {
|
if r := <-resChan; r != 0 {
|
||||||
res = r
|
res = r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return big.NewInt(res)
|
return big.NewInt(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DaggerVerify(hash, diff, nonce *big.Int) bool {
|
func DaggerVerify(hash, diff, nonce *big.Int) bool {
|
||||||
dagger := &Dagger{}
|
dagger := &Dagger{}
|
||||||
dagger.hash = hash
|
dagger.hash = hash
|
||||||
|
|
||||||
obj := ethutil.BigPow(2, 256)
|
obj := ethutil.BigPow(2, 256)
|
||||||
obj = obj.Div(obj, diff)
|
obj = obj.Div(obj, diff)
|
||||||
|
|
||||||
return dagger.Eval(nonce).Cmp(obj) < 0
|
return dagger.Eval(nonce).Cmp(obj) < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dag *Dagger) Node(L uint64, i uint64) *big.Int {
|
func (dag *Dagger) Node(L uint64, i uint64) *big.Int {
|
||||||
if L == i {
|
if L == i {
|
||||||
return dag.hash
|
return dag.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
var m *big.Int
|
var m *big.Int
|
||||||
if L == 9 {
|
if L == 9 {
|
||||||
m = big.NewInt(16)
|
m = big.NewInt(16)
|
||||||
} else {
|
} else {
|
||||||
m = big.NewInt(3)
|
m = big.NewInt(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
sha := sha3.NewKeccak256()
|
sha := sha3.NewKeccak256()
|
||||||
sha.Reset()
|
sha.Reset()
|
||||||
d := sha3.NewKeccak256()
|
d := sha3.NewKeccak256()
|
||||||
b := new(big.Int)
|
b := new(big.Int)
|
||||||
ret := new(big.Int)
|
ret := new(big.Int)
|
||||||
|
|
||||||
for k := 0; k < int(m.Uint64()); k++ {
|
for k := 0; k < int(m.Uint64()); k++ {
|
||||||
d.Reset()
|
d.Reset()
|
||||||
d.Write(dag.hash.Bytes())
|
d.Write(dag.hash.Bytes())
|
||||||
d.Write(dag.xn.Bytes())
|
d.Write(dag.xn.Bytes())
|
||||||
d.Write(big.NewInt(int64(L)).Bytes())
|
d.Write(big.NewInt(int64(L)).Bytes())
|
||||||
d.Write(big.NewInt(int64(i)).Bytes())
|
d.Write(big.NewInt(int64(i)).Bytes())
|
||||||
d.Write(big.NewInt(int64(k)).Bytes())
|
d.Write(big.NewInt(int64(k)).Bytes())
|
||||||
|
|
||||||
b.SetBytes(Sum(d))
|
b.SetBytes(Sum(d))
|
||||||
pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1)
|
pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1)
|
||||||
sha.Write(dag.Node(L - 1, pk).Bytes())
|
sha.Write(dag.Node(L-1, pk).Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.SetBytes(Sum(sha))
|
ret.SetBytes(Sum(sha))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func Sum(sha hash.Hash) []byte {
|
func Sum(sha hash.Hash) []byte {
|
||||||
in := make([]byte, 32)
|
in := make([]byte, 32)
|
||||||
return sha.Sum(in)
|
return sha.Sum(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dag *Dagger) Eval(N *big.Int) *big.Int {
|
func (dag *Dagger) Eval(N *big.Int) *big.Int {
|
||||||
pow := ethutil.BigPow(2, 26)
|
pow := ethutil.BigPow(2, 26)
|
||||||
dag.xn = N.Div(N, pow)
|
dag.xn = N.Div(N, pow)
|
||||||
|
|
||||||
sha := sha3.NewKeccak256()
|
sha := sha3.NewKeccak256()
|
||||||
sha.Reset()
|
sha.Reset()
|
||||||
ret := new(big.Int)
|
ret := new(big.Int)
|
||||||
|
|
||||||
for k := 0; k < 4; k++ {
|
for k := 0; k < 4; k++ {
|
||||||
d := sha3.NewKeccak256()
|
d := sha3.NewKeccak256()
|
||||||
b := new(big.Int)
|
b := new(big.Int)
|
||||||
|
|
||||||
d.Reset()
|
d.Reset()
|
||||||
d.Write(dag.hash.Bytes())
|
d.Write(dag.hash.Bytes())
|
||||||
d.Write(dag.xn.Bytes())
|
d.Write(dag.xn.Bytes())
|
||||||
d.Write(N.Bytes())
|
d.Write(N.Bytes())
|
||||||
d.Write(big.NewInt(int64(k)).Bytes())
|
d.Write(big.NewInt(int64(k)).Bytes())
|
||||||
|
|
||||||
b.SetBytes(Sum(d))
|
b.SetBytes(Sum(d))
|
||||||
pk := (b.Uint64() & 0x1ffffff)
|
pk := (b.Uint64() & 0x1ffffff)
|
||||||
|
|
||||||
sha.Write(dag.Node(9, pk).Bytes())
|
sha.Write(dag.Node(9, pk).Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret.SetBytes(Sum(sha))
|
return ret.SetBytes(Sum(sha))
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"math/big"
|
||||||
"math/big"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkDaggerSearch(b *testing.B) {
|
func BenchmarkDaggerSearch(b *testing.B) {
|
||||||
hash := big.NewInt(0)
|
hash := big.NewInt(0)
|
||||||
diff := BigPow(2, 36)
|
diff := BigPow(2, 36)
|
||||||
o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity
|
o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity
|
||||||
|
|
||||||
// Reset timer so the big generation isn't included in the benchmark
|
// Reset timer so the big generation isn't included in the benchmark
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
// Validate
|
// Validate
|
||||||
DaggerVerify(hash, diff, o)
|
DaggerVerify(hash, diff, o)
|
||||||
}
|
}
|
||||||
|
186
dev_console.go
186
dev_console.go
@ -1,119 +1,121 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"bufio"
|
||||||
"bufio"
|
"encoding/hex"
|
||||||
"strings"
|
"errors"
|
||||||
"os"
|
"fmt"
|
||||||
"errors"
|
"github.com/ethereum/ethdb-go"
|
||||||
"encoding/hex"
|
"github.com/ethereum/ethutil-go"
|
||||||
"github.com/ethereum/ethdb-go"
|
"os"
|
||||||
"github.com/ethereum/ethutil-go"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Console struct {
|
type Console struct {
|
||||||
db *ethdb.MemDatabase
|
db *ethdb.MemDatabase
|
||||||
trie *ethutil.Trie
|
trie *ethutil.Trie
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsole() *Console {
|
func NewConsole() *Console {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
trie := ethutil.NewTrie(db, "")
|
trie := ethutil.NewTrie(db, "")
|
||||||
|
|
||||||
return &Console{db: db, trie: trie}
|
return &Console{db: db, trie: trie}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Console) ValidateInput(action string, argumentLength int) error {
|
func (i *Console) ValidateInput(action string, argumentLength int) error {
|
||||||
err := false
|
err := false
|
||||||
var expArgCount int
|
var expArgCount int
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case action == "update" && argumentLength != 2:
|
case action == "update" && argumentLength != 2:
|
||||||
err = true
|
err = true
|
||||||
expArgCount = 2
|
expArgCount = 2
|
||||||
case action == "get" && argumentLength != 1:
|
case action == "get" && argumentLength != 1:
|
||||||
err = true
|
err = true
|
||||||
expArgCount = 1
|
expArgCount = 1
|
||||||
case action == "dag" && argumentLength != 2:
|
case action == "dag" && argumentLength != 2:
|
||||||
err = true
|
err = true
|
||||||
expArgCount = 2
|
expArgCount = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
if err {
|
if err {
|
||||||
return errors.New(fmt.Sprintf("'%s' requires %d args, got %d", action, expArgCount, argumentLength))
|
return errors.New(fmt.Sprintf("'%s' requires %d args, got %d", action, expArgCount, argumentLength))
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Console) ParseInput(input string) bool {
|
func (i *Console) ParseInput(input string) bool {
|
||||||
scanner := bufio.NewScanner(strings.NewReader(input))
|
scanner := bufio.NewScanner(strings.NewReader(input))
|
||||||
scanner.Split(bufio.ScanWords)
|
scanner.Split(bufio.ScanWords)
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
var tokens []string
|
var tokens []string
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
count++
|
count++
|
||||||
tokens = append(tokens, scanner.Text())
|
tokens = append(tokens, scanner.Text())
|
||||||
}
|
}
|
||||||
if err := scanner.Err(); err != nil {
|
if err := scanner.Err(); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "reading input:", err)
|
fmt.Fprintln(os.Stderr, "reading input:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tokens) == 0 { return true }
|
if len(tokens) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
err := i.ValidateInput(tokens[0], count-1)
|
err := i.ValidateInput(tokens[0], count-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
} else {
|
} else {
|
||||||
switch tokens[0] {
|
switch tokens[0] {
|
||||||
case "update":
|
case "update":
|
||||||
i.trie.Update(tokens[1], tokens[2])
|
i.trie.Update(tokens[1], tokens[2])
|
||||||
|
|
||||||
fmt.Println(hex.EncodeToString([]byte(i.trie.Root)))
|
fmt.Println(hex.EncodeToString([]byte(i.trie.Root)))
|
||||||
case "get":
|
case "get":
|
||||||
fmt.Println(i.trie.Get(tokens[1]))
|
fmt.Println(i.trie.Get(tokens[1]))
|
||||||
case "root":
|
case "root":
|
||||||
fmt.Println(hex.EncodeToString([]byte(i.trie.Root)))
|
fmt.Println(hex.EncodeToString([]byte(i.trie.Root)))
|
||||||
case "rawroot":
|
case "rawroot":
|
||||||
fmt.Println(i.trie.Root)
|
fmt.Println(i.trie.Root)
|
||||||
case "print":
|
case "print":
|
||||||
i.db.Print()
|
i.db.Print()
|
||||||
case "dag":
|
case "dag":
|
||||||
fmt.Println(DaggerVerify( ethutil.Big(tokens[1]), // hash
|
fmt.Println(DaggerVerify(ethutil.Big(tokens[1]), // hash
|
||||||
ethutil.BigPow(2, 36), // diff
|
ethutil.BigPow(2, 36), // diff
|
||||||
ethutil.Big(tokens[2])))// nonce
|
ethutil.Big(tokens[2]))) // nonce
|
||||||
case "exit", "quit", "q":
|
case "exit", "quit", "q":
|
||||||
return false
|
return false
|
||||||
case "help":
|
case "help":
|
||||||
fmt.Printf( "COMMANDS:\n"+
|
fmt.Printf("COMMANDS:\n" +
|
||||||
"\033[1m= DB =\033[0m\n"+
|
"\033[1m= DB =\033[0m\n" +
|
||||||
"update KEY VALUE - Updates/Creates a new value for the given key\n"+
|
"update KEY VALUE - Updates/Creates a new value for the given key\n" +
|
||||||
"get KEY - Retrieves the given key\n"+
|
"get KEY - Retrieves the given key\n" +
|
||||||
"root - Prints the hex encoded merkle root\n"+
|
"root - Prints the hex encoded merkle root\n" +
|
||||||
"rawroot - Prints the raw merkle root\n"+
|
"rawroot - Prints the raw merkle root\n" +
|
||||||
"\033[1m= Dagger =\033[0m\n"+
|
"\033[1m= Dagger =\033[0m\n" +
|
||||||
"dag HASH NONCE - Verifies a nonce with the given hash with dagger\n")
|
"dag HASH NONCE - Verifies a nonce with the given hash with dagger\n")
|
||||||
default:
|
default:
|
||||||
fmt.Println("Unknown command:", tokens[0])
|
fmt.Println("Unknown command:", tokens[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Console) Start() {
|
func (i *Console) Start() {
|
||||||
fmt.Printf("Eth Console. Type (help) for help\n")
|
fmt.Printf("Eth Console. Type (help) for help\n")
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
for {
|
for {
|
||||||
fmt.Printf("eth >>> ")
|
fmt.Printf("eth >>> ")
|
||||||
str, _, err := reader.ReadLine()
|
str, _, err := reader.ReadLine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error reading input", err)
|
fmt.Println("Error reading input", err)
|
||||||
} else {
|
} else {
|
||||||
if !i.ParseInput(string(str)) {
|
if !i.ParseInput(string(str)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
112
ethereum.go
112
ethereum.go
@ -1,85 +1,85 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"flag"
|
||||||
"os"
|
"fmt"
|
||||||
"os/signal"
|
"github.com/ethereum/ethutil-go"
|
||||||
"flag"
|
"log"
|
||||||
"runtime"
|
"os"
|
||||||
"log"
|
"os/signal"
|
||||||
"github.com/ethereum/ethutil-go"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Debug = true
|
const Debug = true
|
||||||
|
|
||||||
var StartConsole bool
|
var StartConsole bool
|
||||||
var StartMining bool
|
var StartMining bool
|
||||||
func Init() {
|
|
||||||
flag.BoolVar(&StartConsole, "c", false, "debug and testing console")
|
|
||||||
flag.BoolVar(&StartMining, "m", false, "start dagger mining")
|
|
||||||
|
|
||||||
flag.Parse()
|
func Init() {
|
||||||
|
flag.BoolVar(&StartConsole, "c", false, "debug and testing console")
|
||||||
|
flag.BoolVar(&StartMining, "m", false, "start dagger mining")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register interrupt handlers so we can stop the server
|
// Register interrupt handlers so we can stop the server
|
||||||
func RegisterInterupts(s *Server) {
|
func RegisterInterupts(s *Server) {
|
||||||
// Buffered chan of one is enough
|
// Buffered chan of one is enough
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
// Notify about interrupts for now
|
// Notify about interrupts for now
|
||||||
signal.Notify(c, os.Interrupt)
|
signal.Notify(c, os.Interrupt)
|
||||||
go func() {
|
go func() {
|
||||||
for sig := range c {
|
for sig := range c {
|
||||||
fmt.Printf("Shutting down (%v) ... \n", sig)
|
fmt.Printf("Shutting down (%v) ... \n", sig)
|
||||||
|
|
||||||
s.Stop()
|
s.Stop()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
||||||
ethutil.InitFees()
|
ethutil.InitFees()
|
||||||
|
|
||||||
Init()
|
Init()
|
||||||
|
|
||||||
if StartConsole {
|
if StartConsole {
|
||||||
console := NewConsole()
|
console := NewConsole()
|
||||||
console.Start()
|
console.Start()
|
||||||
} else{
|
} else {
|
||||||
log.Println("Starting Ethereum")
|
log.Println("Starting Ethereum")
|
||||||
server, err := NewServer()
|
server, err := NewServer()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterInterupts(server)
|
RegisterInterupts(server)
|
||||||
|
|
||||||
if StartMining {
|
if StartMining {
|
||||||
log.Println("Mining started")
|
log.Println("Mining started")
|
||||||
dagger := &Dagger{}
|
dagger := &Dagger{}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
res := dagger.Search(ethutil.Big("0"), ethutil.BigPow(2, 36))
|
res := dagger.Search(ethutil.Big("0"), ethutil.BigPow(2, 36))
|
||||||
server.Broadcast("block", Encode(res.String()))
|
server.Broadcast("block", Encode(res.String()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Start()
|
server.Start()
|
||||||
|
|
||||||
err = server.ConnectToPeer("localhost:12345")
|
err = server.ConnectToPeer("localhost:12345")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
server.Stop()
|
server.Stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for shutdown
|
||||||
// Wait for shutdown
|
server.WaitForShutdown()
|
||||||
server.WaitForShutdown()
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
108
peer.go
108
peer.go
@ -1,92 +1,92 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"github.com/ethereum/ethwire-go"
|
||||||
"log"
|
"log"
|
||||||
"github.com/ethereum/ethwire-go"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
// Server interface
|
// Server interface
|
||||||
server *Server
|
server *Server
|
||||||
// Net connection
|
// Net connection
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
// Output queue which is used to communicate and handle messages
|
// Output queue which is used to communicate and handle messages
|
||||||
outputQueue chan ethwire.InOutMsg
|
outputQueue chan ethwire.InOutMsg
|
||||||
// Quit channel
|
// Quit channel
|
||||||
quit chan bool
|
quit chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPeer(conn net.Conn, server *Server) *Peer {
|
func NewPeer(conn net.Conn, server *Server) *Peer {
|
||||||
return &Peer{
|
return &Peer{
|
||||||
outputQueue: make(chan ethwire.InOutMsg, 1), // Buffered chan of 1 is enough
|
outputQueue: make(chan ethwire.InOutMsg, 1), // Buffered chan of 1 is enough
|
||||||
quit: make(chan bool),
|
quit: make(chan bool),
|
||||||
|
|
||||||
server: server,
|
server: server,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outputs any RLP encoded data to the peer
|
// Outputs any RLP encoded data to the peer
|
||||||
func (p *Peer) QueueMessage(msgType string, data []byte) {
|
func (p *Peer) QueueMessage(msgType string, data []byte) {
|
||||||
p.outputQueue <- ethwire.InOutMsg{MsgType: msgType, Data: data}
|
p.outputQueue <- ethwire.InOutMsg{MsgType: msgType, Data: data}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outbound message handler. Outbound messages are handled here
|
// Outbound message handler. Outbound messages are handled here
|
||||||
func (p *Peer) HandleOutbound() {
|
func (p *Peer) HandleOutbound() {
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
// Main message queue. All outbound messages are processed through here
|
// Main message queue. All outbound messages are processed through here
|
||||||
case msg := <-p.outputQueue:
|
case msg := <-p.outputQueue:
|
||||||
// TODO Message checking and handle accordingly
|
// TODO Message checking and handle accordingly
|
||||||
err := ethwire.WriteMessage(p.conn, msg)
|
err := ethwire.WriteMessage(p.conn, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
|
||||||
// Stop the client if there was an error writing to it
|
// Stop the client if there was an error writing to it
|
||||||
p.Stop()
|
p.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Break out of the for loop if a quit message is posted
|
// Break out of the for loop if a quit message is posted
|
||||||
case <- p.quit:
|
case <-p.quit:
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inbound handler. Inbound messages are received here and passed to the appropriate methods
|
// Inbound handler. Inbound messages are received here and passed to the appropriate methods
|
||||||
func (p *Peer) HandleInbound() {
|
func (p *Peer) HandleInbound() {
|
||||||
defer p.Stop()
|
defer p.Stop()
|
||||||
|
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
// Wait for a message from the peer
|
// Wait for a message from the peer
|
||||||
msg, err := ethwire.ReadMessage(p.conn)
|
msg, err := ethwire.ReadMessage(p.conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
data, _ := Decode(msg.Data, 0)
|
data, _ := Decode(msg.Data, 0)
|
||||||
log.Printf("%s, %s\n", msg.MsgType, data)
|
log.Printf("%s, %s\n", msg.MsgType, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the out handler we're quiting
|
// Notify the out handler we're quiting
|
||||||
p.quit <- true
|
p.quit <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) Start() {
|
func (p *Peer) Start() {
|
||||||
// Run the outbound handler in a new goroutine
|
// Run the outbound handler in a new goroutine
|
||||||
go p.HandleOutbound()
|
go p.HandleOutbound()
|
||||||
// Run the inbound handler in a new goroutine
|
// Run the inbound handler in a new goroutine
|
||||||
go p.HandleInbound()
|
go p.HandleInbound()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) Stop() {
|
func (p *Peer) Stop() {
|
||||||
p.conn.Close()
|
p.conn.Close()
|
||||||
|
|
||||||
p.quit <- true
|
p.quit <- true
|
||||||
}
|
}
|
||||||
|
352
rlp.go
352
rlp.go
@ -1,270 +1,278 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"bytes"
|
||||||
"bytes"
|
"fmt"
|
||||||
"math"
|
"github.com/ethereum/ethutil-go"
|
||||||
"math/big"
|
"math"
|
||||||
"github.com/ethereum/ethutil-go"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RlpEncoder struct {
|
type RlpEncoder struct {
|
||||||
rlpData []byte
|
rlpData []byte
|
||||||
}
|
}
|
||||||
func NewRlpEncoder() *RlpEncoder {
|
|
||||||
encoder := &RlpEncoder{}
|
|
||||||
|
|
||||||
return encoder
|
func NewRlpEncoder() *RlpEncoder {
|
||||||
|
encoder := &RlpEncoder{}
|
||||||
|
|
||||||
|
return encoder
|
||||||
}
|
}
|
||||||
func (coder *RlpEncoder) EncodeData(rlpData []interface{}) []byte {
|
func (coder *RlpEncoder) EncodeData(rlpData []interface{}) []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data attributes are returned by the rlp decoder. The data attributes represents
|
// Data attributes are returned by the rlp decoder. The data attributes represents
|
||||||
// one item within the rlp data structure. It's responsible for all the casting
|
// one item within the rlp data structure. It's responsible for all the casting
|
||||||
// It always returns something valid
|
// It always returns something valid
|
||||||
type RlpDataAttribute struct {
|
type RlpDataAttribute struct {
|
||||||
dataAttrib interface{}
|
dataAttrib interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRlpDataAttribute(attrib interface{}) *RlpDataAttribute {
|
func NewRlpDataAttribute(attrib interface{}) *RlpDataAttribute {
|
||||||
return &RlpDataAttribute{dataAttrib: attrib}
|
return &RlpDataAttribute{dataAttrib: attrib}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (attr *RlpDataAttribute) Length() int {
|
func (attr *RlpDataAttribute) Length() int {
|
||||||
if data, ok := attr.dataAttrib.([]interface{}); ok {
|
if data, ok := attr.dataAttrib.([]interface{}); ok {
|
||||||
return len(data)
|
return len(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (attr *RlpDataAttribute) AsUint() uint64 {
|
func (attr *RlpDataAttribute) AsUint() uint64 {
|
||||||
if value, ok := attr.dataAttrib.(uint8); ok {
|
if value, ok := attr.dataAttrib.(uint8); ok {
|
||||||
return uint64(value)
|
return uint64(value)
|
||||||
} else if value, ok := attr.dataAttrib.(uint16); ok {
|
} else if value, ok := attr.dataAttrib.(uint16); ok {
|
||||||
return uint64(value)
|
return uint64(value)
|
||||||
} else if value, ok := attr.dataAttrib.(uint32); ok {
|
} else if value, ok := attr.dataAttrib.(uint32); ok {
|
||||||
return uint64(value)
|
return uint64(value)
|
||||||
} else if value, ok := attr.dataAttrib.(uint64); ok {
|
} else if value, ok := attr.dataAttrib.(uint64); ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (attr *RlpDataAttribute) AsBigInt() *big.Int {
|
func (attr *RlpDataAttribute) AsBigInt() *big.Int {
|
||||||
if a, ok := attr.dataAttrib.([]byte); ok {
|
if a, ok := attr.dataAttrib.([]byte); ok {
|
||||||
return ethutil.Big(string(a))
|
return ethutil.Big(string(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
return big.NewInt(0)
|
return big.NewInt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (attr *RlpDataAttribute) AsString() string {
|
func (attr *RlpDataAttribute) AsString() string {
|
||||||
if a, ok := attr.dataAttrib.([]byte); ok {
|
if a, ok := attr.dataAttrib.([]byte); ok {
|
||||||
return string(a)
|
return string(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (attr *RlpDataAttribute) AsBytes() []byte {
|
func (attr *RlpDataAttribute) AsBytes() []byte {
|
||||||
if a, ok := attr.dataAttrib.([]byte); ok {
|
if a, ok := attr.dataAttrib.([]byte); ok {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
return make([]byte, 0)
|
return make([]byte, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Threat the attribute as a slice
|
// Threat the attribute as a slice
|
||||||
func (attr *RlpDataAttribute) Get(idx int) *RlpDataAttribute {
|
func (attr *RlpDataAttribute) Get(idx int) *RlpDataAttribute {
|
||||||
if d, ok := attr.dataAttrib.([]interface{}); ok {
|
if d, ok := attr.dataAttrib.([]interface{}); ok {
|
||||||
// Guard for oob
|
// Guard for oob
|
||||||
if len(d) < idx {
|
if len(d) < idx {
|
||||||
return NewRlpDataAttribute(nil)
|
return NewRlpDataAttribute(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewRlpDataAttribute(d[idx])
|
return NewRlpDataAttribute(d[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this wasn't a slice you probably shouldn't be using this function
|
// If this wasn't a slice you probably shouldn't be using this function
|
||||||
return NewRlpDataAttribute(nil)
|
return NewRlpDataAttribute(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RlpDecoder struct {
|
type RlpDecoder struct {
|
||||||
rlpData interface{}
|
rlpData interface{}
|
||||||
}
|
}
|
||||||
func NewRlpDecoder(rlpData []byte) *RlpDecoder {
|
|
||||||
decoder := &RlpDecoder{}
|
|
||||||
// Decode the data
|
|
||||||
data, _ := Decode(rlpData,0)
|
|
||||||
decoder.rlpData = data
|
|
||||||
|
|
||||||
return decoder
|
func NewRlpDecoder(rlpData []byte) *RlpDecoder {
|
||||||
|
decoder := &RlpDecoder{}
|
||||||
|
// Decode the data
|
||||||
|
data, _ := Decode(rlpData, 0)
|
||||||
|
decoder.rlpData = data
|
||||||
|
|
||||||
|
return decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dec *RlpDecoder) Get(idx int) *RlpDataAttribute {
|
func (dec *RlpDecoder) Get(idx int) *RlpDataAttribute {
|
||||||
return NewRlpDataAttribute(dec.rlpData).Get(idx)
|
return NewRlpDataAttribute(dec.rlpData).Get(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw methods
|
/// Raw methods
|
||||||
func BinaryLength(n uint64) uint64 {
|
func BinaryLength(n uint64) uint64 {
|
||||||
if n == 0 { return 0 }
|
if n == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
return 1 + BinaryLength(n / 256)
|
return 1 + BinaryLength(n/256)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToBinarySlice(n uint64, length uint64) []uint64 {
|
func ToBinarySlice(n uint64, length uint64) []uint64 {
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
length = BinaryLength(n)
|
length = BinaryLength(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if n == 0 { return make([]uint64, 1) }
|
if n == 0 {
|
||||||
|
return make([]uint64, 1)
|
||||||
|
}
|
||||||
|
|
||||||
slice := ToBinarySlice(n / 256, 0)
|
slice := ToBinarySlice(n/256, 0)
|
||||||
slice = append(slice, n % 256)
|
slice = append(slice, n%256)
|
||||||
|
|
||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToBin(n uint64, length uint64) string {
|
func ToBin(n uint64, length uint64) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
for _, val := range ToBinarySlice(n, length) {
|
for _, val := range ToBinarySlice(n, length) {
|
||||||
buf.WriteString(string(val))
|
buf.WriteString(string(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromBin(data []byte) uint64 {
|
func FromBin(data []byte) uint64 {
|
||||||
if len(data) == 0 { return 0 }
|
if len(data) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
return FromBin(data[:len(data)-1]) * 256 + uint64(data[len(data)-1])
|
return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func Decode(data []byte, pos int) (interface{}, int) {
|
func Decode(data []byte, pos int) (interface{}, int) {
|
||||||
if pos > len(data)-1 {
|
if pos > len(data)-1 {
|
||||||
panic(fmt.Sprintf("index out of range %d for data %q, l = %d", pos, data, len(data)))
|
panic(fmt.Sprintf("index out of range %d for data %q, l = %d", pos, data, len(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
char := int(data[pos])
|
char := int(data[pos])
|
||||||
slice := make([]interface{}, 0)
|
slice := make([]interface{}, 0)
|
||||||
switch {
|
switch {
|
||||||
case char < 24:
|
case char < 24:
|
||||||
return data[pos], pos + 1
|
return data[pos], pos + 1
|
||||||
|
|
||||||
case char < 56:
|
case char < 56:
|
||||||
b := int(data[pos]) - 23
|
b := int(data[pos]) - 23
|
||||||
return FromBin(data[pos+1 : pos+1+b]), pos + 1 + b
|
return FromBin(data[pos+1 : pos+1+b]), pos + 1 + b
|
||||||
|
|
||||||
case char < 64:
|
case char < 64:
|
||||||
b := int(data[pos]) - 55
|
b := int(data[pos]) - 55
|
||||||
b2 := int(FromBin(data[pos+1 : pos+1+b]))
|
b2 := int(FromBin(data[pos+1 : pos+1+b]))
|
||||||
return FromBin(data[pos+1+b : pos+1+b+b2]), pos+1+b+b2
|
return FromBin(data[pos+1+b : pos+1+b+b2]), pos + 1 + b + b2
|
||||||
|
|
||||||
case char < 120:
|
case char < 120:
|
||||||
b := int(data[pos]) - 64
|
b := int(data[pos]) - 64
|
||||||
return data[pos+1:pos+1+b], pos+1+b
|
return data[pos+1 : pos+1+b], pos + 1 + b
|
||||||
|
|
||||||
case char < 128:
|
case char < 128:
|
||||||
b := int(data[pos]) - 119
|
b := int(data[pos]) - 119
|
||||||
b2 := int(FromBin(data[pos+1 : pos+1+b]))
|
b2 := int(FromBin(data[pos+1 : pos+1+b]))
|
||||||
return data[pos+1+b : pos+1+b+b2], pos+1+b+b2
|
return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2
|
||||||
|
|
||||||
case char < 184:
|
case char < 184:
|
||||||
b := int(data[pos]) - 128
|
b := int(data[pos]) - 128
|
||||||
pos++
|
pos++
|
||||||
for i := 0; i < b; i++ {
|
for i := 0; i < b; i++ {
|
||||||
var obj interface{}
|
var obj interface{}
|
||||||
|
|
||||||
obj, pos = Decode(data, pos)
|
obj, pos = Decode(data, pos)
|
||||||
slice = append(slice, obj)
|
slice = append(slice, obj)
|
||||||
}
|
}
|
||||||
return slice, pos
|
return slice, pos
|
||||||
|
|
||||||
case char < 192:
|
case char < 192:
|
||||||
b := int(data[pos]) - 183
|
b := int(data[pos]) - 183
|
||||||
//b2 := int(FromBin(data[pos+1 : pos+1+b])) (ref implementation has an unused variable)
|
//b2 := int(FromBin(data[pos+1 : pos+1+b])) (ref implementation has an unused variable)
|
||||||
pos = pos+1+b
|
pos = pos + 1 + b
|
||||||
for i := 0; i < b; i++ {
|
for i := 0; i < b; i++ {
|
||||||
var obj interface{}
|
var obj interface{}
|
||||||
|
|
||||||
obj, pos = Decode(data, pos)
|
obj, pos = Decode(data, pos)
|
||||||
slice = append(slice, obj)
|
slice = append(slice, obj)
|
||||||
}
|
}
|
||||||
return slice, pos
|
return slice, pos
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("byte not supported: %q", char))
|
panic(fmt.Sprintf("byte not supported: %q", char))
|
||||||
}
|
}
|
||||||
|
|
||||||
return slice, 0
|
return slice, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func Encode(object interface{}) []byte {
|
func Encode(object interface{}) []byte {
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
|
|
||||||
switch t := object.(type) {
|
switch t := object.(type) {
|
||||||
case uint32, uint64:
|
case uint32, uint64:
|
||||||
var num uint64
|
var num uint64
|
||||||
if _num, ok := t.(uint64); ok {
|
if _num, ok := t.(uint64); ok {
|
||||||
num = _num
|
num = _num
|
||||||
} else if _num, ok := t.(uint32); ok {
|
} else if _num, ok := t.(uint32); ok {
|
||||||
num = uint64(_num)
|
num = uint64(_num)
|
||||||
}
|
}
|
||||||
|
|
||||||
if num >= 0 && num < 24 {
|
if num >= 0 && num < 24 {
|
||||||
buff.WriteString(string(num))
|
buff.WriteString(string(num))
|
||||||
} else if num <= uint64(math.Pow(2, 256)) {
|
} else if num <= uint64(math.Pow(2, 256)) {
|
||||||
b := ToBin(num, 0)
|
b := ToBin(num, 0)
|
||||||
buff.WriteString(string(len(b) + 23) + b)
|
buff.WriteString(string(len(b)+23) + b)
|
||||||
} else {
|
} else {
|
||||||
b := ToBin(num, 0)
|
b := ToBin(num, 0)
|
||||||
b2 := ToBin(uint64(len(b)), 0)
|
b2 := ToBin(uint64(len(b)), 0)
|
||||||
buff.WriteString(string(len(b2) + 55) + b2 + b)
|
buff.WriteString(string(len(b2)+55) + b2 + b)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *big.Int:
|
case *big.Int:
|
||||||
buff.Write(Encode(t.String()))
|
buff.Write(Encode(t.String()))
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if len(t) < 56 {
|
if len(t) < 56 {
|
||||||
buff.WriteString(string(len(t) + 64) + t)
|
buff.WriteString(string(len(t)+64) + t)
|
||||||
} else {
|
} else {
|
||||||
b2 := ToBin(uint64(len(t)), 0)
|
b2 := ToBin(uint64(len(t)), 0)
|
||||||
buff.WriteString(string(len(b2) + 119) + b2 + t)
|
buff.WriteString(string(len(b2)+119) + b2 + t)
|
||||||
}
|
}
|
||||||
|
|
||||||
case []byte:
|
case []byte:
|
||||||
// Cast the byte slice to a string
|
// Cast the byte slice to a string
|
||||||
buff.Write(Encode(string(t)))
|
buff.Write(Encode(string(t)))
|
||||||
|
|
||||||
case []interface{}, []string:
|
case []interface{}, []string:
|
||||||
// Inline function for writing the slice header
|
// Inline function for writing the slice header
|
||||||
WriteSliceHeader := func(length int) {
|
WriteSliceHeader := func(length int) {
|
||||||
if length < 56 {
|
if length < 56 {
|
||||||
buff.WriteByte(byte(length + 128))
|
buff.WriteByte(byte(length + 128))
|
||||||
} else {
|
} else {
|
||||||
b2 := ToBin(uint64(length), 0)
|
b2 := ToBin(uint64(length), 0)
|
||||||
buff.WriteByte(byte(len(b2) + 183))
|
buff.WriteByte(byte(len(b2) + 183))
|
||||||
buff.WriteString(b2)
|
buff.WriteString(b2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME How can I do this "better"?
|
// FIXME How can I do this "better"?
|
||||||
if interSlice, ok := t.([]interface{}); ok {
|
if interSlice, ok := t.([]interface{}); ok {
|
||||||
WriteSliceHeader(len(interSlice))
|
WriteSliceHeader(len(interSlice))
|
||||||
for _, val := range interSlice {
|
for _, val := range interSlice {
|
||||||
buff.Write(Encode(val))
|
buff.Write(Encode(val))
|
||||||
}
|
}
|
||||||
} else if stringSlice, ok := t.([]string); ok {
|
} else if stringSlice, ok := t.([]string); ok {
|
||||||
WriteSliceHeader(len(stringSlice))
|
WriteSliceHeader(len(stringSlice))
|
||||||
for _, val := range stringSlice {
|
for _, val := range stringSlice {
|
||||||
buff.Write(Encode(val))
|
buff.Write(Encode(val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buff.Bytes()
|
return buff.Bytes()
|
||||||
}
|
}
|
||||||
|
70
rlp_test.go
70
rlp_test.go
@ -1,54 +1,54 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"fmt"
|
||||||
"fmt"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncode(t *testing.T) {
|
func TestEncode(t *testing.T) {
|
||||||
strRes := "Cdog"
|
strRes := "Cdog"
|
||||||
|
|
||||||
bytes := Encode("dog")
|
bytes := Encode("dog")
|
||||||
|
|
||||||
str := string(bytes)
|
str := string(bytes)
|
||||||
if str != strRes {
|
if str != strRes {
|
||||||
t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str))
|
t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str))
|
||||||
}
|
}
|
||||||
//dec,_ := Decode(bytes, 0)
|
//dec,_ := Decode(bytes, 0)
|
||||||
|
|
||||||
sliceRes := "\x83CdogCgodCcat"
|
sliceRes := "\x83CdogCgodCcat"
|
||||||
strs := []string{"dog", "god", "cat"}
|
strs := []string{"dog", "god", "cat"}
|
||||||
bytes = Encode(strs)
|
bytes = Encode(strs)
|
||||||
slice := string(bytes)
|
slice := string(bytes)
|
||||||
if slice != sliceRes {
|
if slice != sliceRes {
|
||||||
t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice))
|
t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice))
|
||||||
}
|
}
|
||||||
|
|
||||||
//dec,_ = Decode(bytes, 0)
|
//dec,_ = Decode(bytes, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiEncode(t *testing.T) {
|
func TestMultiEncode(t *testing.T) {
|
||||||
inter := []interface{}{
|
inter := []interface{}{
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
"1","2","3",
|
"1", "2", "3",
|
||||||
},
|
},
|
||||||
[]string{
|
[]string{
|
||||||
"string",
|
"string",
|
||||||
"string2",
|
"string2",
|
||||||
"\x86A0J1234567890A\x00B20A0\x82F395843F657986",
|
"\x86A0J1234567890A\x00B20A0\x82F395843F657986",
|
||||||
"\x86A0J1234567890A\x00B20A0\x8cF395843F657986I335612448F524099H16716881A0H13114947G2039362G1507139H16719697G1048387E65360",
|
"\x86A0J1234567890A\x00B20A0\x8cF395843F657986I335612448F524099H16716881A0H13114947G2039362G1507139H16719697G1048387E65360",
|
||||||
},
|
},
|
||||||
"test",
|
"test",
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes := Encode(inter)
|
bytes := Encode(inter)
|
||||||
|
|
||||||
Decode(bytes, 0)
|
Decode(bytes, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkEncodeDecode(b *testing.B) {
|
func BenchmarkEncodeDecode(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
bytes := Encode([]string{"dog", "god", "cat"})
|
bytes := Encode([]string{"dog", "god", "cat"})
|
||||||
Decode(bytes, 0)
|
Decode(bytes, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
155
server.go
155
server.go
@ -1,121 +1,120 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"net"
|
"github.com/ethereum/ethdb-go"
|
||||||
"log"
|
"github.com/ethereum/ethutil-go"
|
||||||
_"time"
|
"log"
|
||||||
"github.com/ethereum/ethdb-go"
|
"net"
|
||||||
"github.com/ethereum/ethutil-go"
|
_ "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
// Channel for shutting down the server
|
// Channel for shutting down the server
|
||||||
shutdownChan chan bool
|
shutdownChan chan bool
|
||||||
// DB interface
|
// DB interface
|
||||||
db *ethdb.LDBDatabase
|
db *ethdb.LDBDatabase
|
||||||
// Block manager for processing new blocks and managing the block chain
|
// Block manager for processing new blocks and managing the block chain
|
||||||
blockManager *BlockManager
|
blockManager *BlockManager
|
||||||
// Peers (NYI)
|
// Peers (NYI)
|
||||||
peers *list.List
|
peers *list.List
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer() (*Server, error) {
|
func NewServer() (*Server, error) {
|
||||||
db, err := ethdb.NewLDBDatabase()
|
db, err := ethdb.NewLDBDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ethutil.SetConfig(db)
|
ethutil.SetConfig(db)
|
||||||
|
|
||||||
server := &Server{
|
server := &Server{
|
||||||
shutdownChan: make(chan bool),
|
shutdownChan: make(chan bool),
|
||||||
blockManager: NewBlockManager(),
|
blockManager: NewBlockManager(),
|
||||||
db: db,
|
db: db,
|
||||||
peers: list.New(),
|
peers: list.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return server, nil
|
return server, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AddPeer(conn net.Conn) {
|
func (s *Server) AddPeer(conn net.Conn) {
|
||||||
peer := NewPeer(conn, s)
|
peer := NewPeer(conn, s)
|
||||||
s.peers.PushBack(peer)
|
s.peers.PushBack(peer)
|
||||||
peer.Start()
|
peer.Start()
|
||||||
|
|
||||||
log.Println("Peer connected ::", conn.RemoteAddr())
|
log.Println("Peer connected ::", conn.RemoteAddr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ConnectToPeer(addr string) error {
|
func (s *Server) ConnectToPeer(addr string) error {
|
||||||
conn, err := net.Dial("tcp", addr)
|
conn, err := net.Dial("tcp", addr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
peer := NewPeer(conn, s)
|
peer := NewPeer(conn, s)
|
||||||
s.peers.PushBack(peer)
|
s.peers.PushBack(peer)
|
||||||
peer.Start()
|
peer.Start()
|
||||||
|
|
||||||
|
log.Println("Connected to peer ::", conn.RemoteAddr())
|
||||||
|
|
||||||
log.Println("Connected to peer ::", conn.RemoteAddr())
|
return nil
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Broadcast(msgType string, data []byte) {
|
func (s *Server) Broadcast(msgType string, data []byte) {
|
||||||
for e := s.peers.Front(); e != nil; e = e.Next() {
|
for e := s.peers.Front(); e != nil; e = e.Next() {
|
||||||
if peer, ok := e.Value.(*Peer); ok {
|
if peer, ok := e.Value.(*Peer); ok {
|
||||||
peer.QueueMessage(msgType, data)
|
peer.QueueMessage(msgType, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
func (s *Server) Start() {
|
func (s *Server) Start() {
|
||||||
// For now this function just blocks the main thread
|
// For now this function just blocks the main thread
|
||||||
ln, err := net.Listen("tcp", ":12345")
|
ln, err := net.Listen("tcp", ":12345")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
conn, err := ln.Accept()
|
conn, err := ln.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
go s.AddPeer(conn)
|
go s.AddPeer(conn)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// TMP
|
// TMP
|
||||||
//go func() {
|
//go func() {
|
||||||
// for {
|
// for {
|
||||||
// s.Broadcast("block", Encode("blockdata"))
|
// s.Broadcast("block", Encode("blockdata"))
|
||||||
//
|
//
|
||||||
// time.Sleep(100 * time.Millisecond)
|
// time.Sleep(100 * time.Millisecond)
|
||||||
// }
|
// }
|
||||||
// }()
|
// }()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Stop() {
|
func (s *Server) Stop() {
|
||||||
// Close the database
|
// Close the database
|
||||||
defer s.db.Close()
|
defer s.db.Close()
|
||||||
|
|
||||||
// Loop thru the peers and close them (if we had them)
|
// Loop thru the peers and close them (if we had them)
|
||||||
for e := s.peers.Front(); e != nil; e = e.Next() {
|
for e := s.peers.Front(); e != nil; e = e.Next() {
|
||||||
if peer, ok := e.Value.(*Peer); ok {
|
if peer, ok := e.Value.(*Peer); ok {
|
||||||
peer.Stop()
|
peer.Stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.shutdownChan <- true
|
s.shutdownChan <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will wait for a shutdown and resumes main thread execution
|
// This function will wait for a shutdown and resumes main thread execution
|
||||||
func (s *Server) WaitForShutdown() {
|
func (s *Server) WaitForShutdown() {
|
||||||
<- s.shutdownChan
|
<-s.shutdownChan
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"encoding/json"
|
||||||
"testing"
|
"fmt"
|
||||||
"encoding/json"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestSource struct {
|
type TestSource struct {
|
||||||
Inputs map[string]string
|
Inputs map[string]string
|
||||||
Expectation string
|
Expectation string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestSource(source string) *TestSource {
|
func NewTestSource(source string) *TestSource {
|
||||||
s := &TestSource{}
|
s := &TestSource{}
|
||||||
err := json.Unmarshal([]byte(source), s)
|
err := json.Unmarshal([]byte(source), s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestRunner struct {
|
type TestRunner struct {
|
||||||
source *TestSource
|
source *TestSource
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestRunner(t *testing.T) *TestRunner {
|
func NewTestRunner(t *testing.T) *TestRunner {
|
||||||
return &TestRunner{}
|
return &TestRunner{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (runner *TestRunner) RunFromString(input string, Cb func(*TestSource)) {
|
func (runner *TestRunner) RunFromString(input string, Cb func(*TestSource)) {
|
||||||
source := NewTestSource(input)
|
source := NewTestSource(input)
|
||||||
Cb(source)
|
Cb(source)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_"fmt"
|
"encoding/hex"
|
||||||
"testing"
|
_ "fmt"
|
||||||
"encoding/hex"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testsource = `{"Inputs":{
|
var testsource = `{"Inputs":{
|
||||||
@ -15,17 +15,17 @@ var testsource = `{"Inputs":{
|
|||||||
}`
|
}`
|
||||||
|
|
||||||
func TestTestRunner(t *testing.T) {
|
func TestTestRunner(t *testing.T) {
|
||||||
db, _ := NewMemDatabase()
|
db, _ := NewMemDatabase()
|
||||||
trie := NewTrie(db, "")
|
trie := NewTrie(db, "")
|
||||||
|
|
||||||
runner := NewTestRunner(t)
|
runner := NewTestRunner(t)
|
||||||
runner.RunFromString(testsource, func(source *TestSource) {
|
runner.RunFromString(testsource, func(source *TestSource) {
|
||||||
for key, value := range source.Inputs {
|
for key, value := range source.Inputs {
|
||||||
trie.Update(key, value)
|
trie.Update(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hex.EncodeToString([]byte(trie.root)) != source.Expectation {
|
if hex.EncodeToString([]byte(trie.root)) != source.Expectation {
|
||||||
t.Error("trie root did not match")
|
t.Error("trie root did not match")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
451
vm.go
451
vm.go
@ -1,267 +1,284 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"fmt"
|
||||||
"fmt"
|
"github.com/ethereum/ethutil-go"
|
||||||
"strconv"
|
"math/big"
|
||||||
"github.com/ethereum/ethutil-go"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Op codes
|
// Op codes
|
||||||
const (
|
const (
|
||||||
oSTOP int = 0x00
|
oSTOP int = 0x00
|
||||||
oADD int = 0x01
|
oADD int = 0x01
|
||||||
oMUL int = 0x02
|
oMUL int = 0x02
|
||||||
oSUB int = 0x03
|
oSUB int = 0x03
|
||||||
oDIV int = 0x04
|
oDIV int = 0x04
|
||||||
oSDIV int = 0x05
|
oSDIV int = 0x05
|
||||||
oMOD int = 0x06
|
oMOD int = 0x06
|
||||||
oSMOD int = 0x07
|
oSMOD int = 0x07
|
||||||
oEXP int = 0x08
|
oEXP int = 0x08
|
||||||
oNEG int = 0x09
|
oNEG int = 0x09
|
||||||
oLT int = 0x0a
|
oLT int = 0x0a
|
||||||
oLE int = 0x0b
|
oLE int = 0x0b
|
||||||
oGT int = 0x0c
|
oGT int = 0x0c
|
||||||
oGE int = 0x0d
|
oGE int = 0x0d
|
||||||
oEQ int = 0x0e
|
oEQ int = 0x0e
|
||||||
oNOT int = 0x0f
|
oNOT int = 0x0f
|
||||||
oMYADDRESS int = 0x10
|
oMYADDRESS int = 0x10
|
||||||
oTXSENDER int = 0x11
|
oTXSENDER int = 0x11
|
||||||
oTXVALUE int = 0x12
|
oTXVALUE int = 0x12
|
||||||
oTXFEE int = 0x13
|
oTXFEE int = 0x13
|
||||||
oTXDATAN int = 0x14
|
oTXDATAN int = 0x14
|
||||||
oTXDATA int = 0x15
|
oTXDATA int = 0x15
|
||||||
oBLK_PREVHASH int = 0x16
|
oBLK_PREVHASH int = 0x16
|
||||||
oBLK_COINBASE int = 0x17
|
oBLK_COINBASE int = 0x17
|
||||||
oBLK_TIMESTAMP int = 0x18
|
oBLK_TIMESTAMP int = 0x18
|
||||||
oBLK_NUMBER int = 0x19
|
oBLK_NUMBER int = 0x19
|
||||||
oBLK_DIFFICULTY int = 0x1a
|
oBLK_DIFFICULTY int = 0x1a
|
||||||
oSHA256 int = 0x20
|
oSHA256 int = 0x20
|
||||||
oRIPEMD160 int = 0x21
|
oRIPEMD160 int = 0x21
|
||||||
oECMUL int = 0x22
|
oECMUL int = 0x22
|
||||||
oECADD int = 0x23
|
oECADD int = 0x23
|
||||||
oECSIGN int = 0x24
|
oECSIGN int = 0x24
|
||||||
oECRECOVER int = 0x25
|
oECRECOVER int = 0x25
|
||||||
oECVALID int = 0x26
|
oECVALID int = 0x26
|
||||||
oPUSH int = 0x30
|
oPUSH int = 0x30
|
||||||
oPOP int = 0x31
|
oPOP int = 0x31
|
||||||
oDUP int = 0x32
|
oDUP int = 0x32
|
||||||
oDUPN int = 0x33
|
oDUPN int = 0x33
|
||||||
oSWAP int = 0x34
|
oSWAP int = 0x34
|
||||||
oSWAPN int = 0x35
|
oSWAPN int = 0x35
|
||||||
oLOAD int = 0x36
|
oLOAD int = 0x36
|
||||||
oSTORE int = 0x37
|
oSTORE int = 0x37
|
||||||
oJMP int = 0x40
|
oJMP int = 0x40
|
||||||
oJMPI int = 0x41
|
oJMPI int = 0x41
|
||||||
oIND int = 0x42
|
oIND int = 0x42
|
||||||
oEXTRO int = 0x50
|
oEXTRO int = 0x50
|
||||||
oBALANCE int = 0x51
|
oBALANCE int = 0x51
|
||||||
oMKTX int = 0x60
|
oMKTX int = 0x60
|
||||||
oSUICIDE int = 0xff
|
oSUICIDE int = 0xff
|
||||||
)
|
)
|
||||||
|
|
||||||
type OpType int
|
type OpType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tNorm = iota
|
tNorm = iota
|
||||||
tData
|
tData
|
||||||
tExtro
|
tExtro
|
||||||
tCrypto
|
tCrypto
|
||||||
)
|
)
|
||||||
|
|
||||||
type TxCallback func(opType OpType) bool
|
type TxCallback func(opType OpType) bool
|
||||||
|
|
||||||
// Simple push/pop stack mechanism
|
// Simple push/pop stack mechanism
|
||||||
type Stack struct {
|
type Stack struct {
|
||||||
data []string
|
data []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStack() *Stack {
|
func NewStack() *Stack {
|
||||||
return &Stack{}
|
return &Stack{}
|
||||||
}
|
}
|
||||||
func (st *Stack) Pop() string {
|
func (st *Stack) Pop() string {
|
||||||
s := len(st.data)
|
s := len(st.data)
|
||||||
|
|
||||||
str := st.data[s-1]
|
str := st.data[s-1]
|
||||||
st.data = st.data[:s-1]
|
st.data = st.data[:s-1]
|
||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) Popn() (*big.Int, *big.Int) {
|
func (st *Stack) Popn() (*big.Int, *big.Int) {
|
||||||
s := len(st.data)
|
s := len(st.data)
|
||||||
|
|
||||||
strs := st.data[s-2:]
|
strs := st.data[s-2:]
|
||||||
st.data = st.data[:s-2]
|
st.data = st.data[:s-2]
|
||||||
|
|
||||||
return ethutil.Big(strs[0]), ethutil.Big(strs[1])
|
return ethutil.Big(strs[0]), ethutil.Big(strs[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) Push(d string) {
|
func (st *Stack) Push(d string) {
|
||||||
st.data = append(st.data, d)
|
st.data = append(st.data, d)
|
||||||
}
|
}
|
||||||
func (st *Stack) Print() {
|
func (st *Stack) Print() {
|
||||||
fmt.Println(st.data)
|
fmt.Println(st.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Vm struct {
|
type Vm struct {
|
||||||
// Stack
|
// Stack
|
||||||
stack *Stack
|
stack *Stack
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVm() *Vm {
|
func NewVm() *Vm {
|
||||||
return &Vm{
|
return &Vm{
|
||||||
stack: NewStack(),
|
stack: NewStack(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *Vm) ProcContract( tx *ethutil.Transaction,
|
func (vm *Vm) ProcContract(tx *ethutil.Transaction,
|
||||||
block *ethutil.Block, cb TxCallback) {
|
block *ethutil.Block, cb TxCallback) {
|
||||||
// Instruction pointer
|
// Instruction pointer
|
||||||
pc := 0
|
pc := 0
|
||||||
|
|
||||||
contract := block.GetContract(tx.Hash())
|
contract := block.GetContract(tx.Hash())
|
||||||
if contract == nil {
|
if contract == nil {
|
||||||
fmt.Println("Contract not found")
|
fmt.Println("Contract not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Pow256 := ethutil.BigPow(2, 256)
|
Pow256 := ethutil.BigPow(2, 256)
|
||||||
|
|
||||||
//fmt.Printf("# op arg\n")
|
//fmt.Printf("# op arg\n")
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
// The base big int for all calculations. Use this for any results.
|
// The base big int for all calculations. Use this for any results.
|
||||||
base := new(big.Int)
|
base := new(big.Int)
|
||||||
// XXX Should Instr return big int slice instead of string slice?
|
// XXX Should Instr return big int slice instead of string slice?
|
||||||
// Get the next instruction from the contract
|
// Get the next instruction from the contract
|
||||||
//op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
|
//op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
|
||||||
nb := ethutil.NumberToBytes(uint64(pc), 32)
|
nb := ethutil.NumberToBytes(uint64(pc), 32)
|
||||||
op, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
|
op, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
|
||||||
|
|
||||||
if !cb(0) { break }
|
if !cb(0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
//fmt.Printf("%-3d %-4d\n", pc, op)
|
//fmt.Printf("%-3d %-4d\n", pc, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case oADD:
|
case oADD:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// (x + y) % 2 ** 256
|
// (x + y) % 2 ** 256
|
||||||
base.Add(x, y)
|
base.Add(x, y)
|
||||||
base.Mod(base, Pow256)
|
base.Mod(base, Pow256)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oSUB:
|
case oSUB:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// (x - y) % 2 ** 256
|
// (x - y) % 2 ** 256
|
||||||
base.Sub(x, y)
|
base.Sub(x, y)
|
||||||
base.Mod(base, Pow256)
|
base.Mod(base, Pow256)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oMUL:
|
case oMUL:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// (x * y) % 2 ** 256
|
// (x * y) % 2 ** 256
|
||||||
base.Mul(x, y)
|
base.Mul(x, y)
|
||||||
base.Mod(base, Pow256)
|
base.Mod(base, Pow256)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oDIV:
|
case oDIV:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// floor(x / y)
|
// floor(x / y)
|
||||||
base.Div(x, y)
|
base.Div(x, y)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oSDIV:
|
case oSDIV:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// n > 2**255
|
// n > 2**255
|
||||||
if x.Cmp(Pow256) > 0 { x.Sub(Pow256, x) }
|
if x.Cmp(Pow256) > 0 {
|
||||||
if y.Cmp(Pow256) > 0 { y.Sub(Pow256, y) }
|
x.Sub(Pow256, x)
|
||||||
z := new(big.Int)
|
}
|
||||||
z.Div(x, y)
|
if y.Cmp(Pow256) > 0 {
|
||||||
if z.Cmp(Pow256) > 0 { z.Sub(Pow256, z) }
|
y.Sub(Pow256, y)
|
||||||
// Push result on to the stack
|
}
|
||||||
vm.stack.Push(z.String())
|
z := new(big.Int)
|
||||||
case oMOD:
|
z.Div(x, y)
|
||||||
x, y := vm.stack.Popn()
|
if z.Cmp(Pow256) > 0 {
|
||||||
base.Mod(x, y)
|
z.Sub(Pow256, z)
|
||||||
vm.stack.Push(base.String())
|
}
|
||||||
case oSMOD:
|
// Push result on to the stack
|
||||||
x, y := vm.stack.Popn()
|
vm.stack.Push(z.String())
|
||||||
// n > 2**255
|
case oMOD:
|
||||||
if x.Cmp(Pow256) > 0 { x.Sub(Pow256, x) }
|
x, y := vm.stack.Popn()
|
||||||
if y.Cmp(Pow256) > 0 { y.Sub(Pow256, y) }
|
base.Mod(x, y)
|
||||||
z := new(big.Int)
|
vm.stack.Push(base.String())
|
||||||
z.Mod(x, y)
|
case oSMOD:
|
||||||
if z.Cmp(Pow256) > 0 { z.Sub(Pow256, z) }
|
x, y := vm.stack.Popn()
|
||||||
// Push result on to the stack
|
// n > 2**255
|
||||||
vm.stack.Push(z.String())
|
if x.Cmp(Pow256) > 0 {
|
||||||
case oEXP:
|
x.Sub(Pow256, x)
|
||||||
x, y := vm.stack.Popn()
|
}
|
||||||
base.Exp(x, y, Pow256)
|
if y.Cmp(Pow256) > 0 {
|
||||||
|
y.Sub(Pow256, y)
|
||||||
|
}
|
||||||
|
z := new(big.Int)
|
||||||
|
z.Mod(x, y)
|
||||||
|
if z.Cmp(Pow256) > 0 {
|
||||||
|
z.Sub(Pow256, z)
|
||||||
|
}
|
||||||
|
// Push result on to the stack
|
||||||
|
vm.stack.Push(z.String())
|
||||||
|
case oEXP:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
base.Exp(x, y, Pow256)
|
||||||
|
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oNEG:
|
case oNEG:
|
||||||
base.Sub(Pow256, ethutil.Big(vm.stack.Pop()))
|
base.Sub(Pow256, ethutil.Big(vm.stack.Pop()))
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oLT:
|
case oLT:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// x < y
|
// x < y
|
||||||
if x.Cmp(y) < 0 {
|
if x.Cmp(y) < 0 {
|
||||||
vm.stack.Push("1")
|
vm.stack.Push("1")
|
||||||
} else {
|
} else {
|
||||||
vm.stack.Push("0")
|
vm.stack.Push("0")
|
||||||
}
|
}
|
||||||
case oLE:
|
case oLE:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// x <= y
|
// x <= y
|
||||||
if x.Cmp(y) < 1 {
|
if x.Cmp(y) < 1 {
|
||||||
vm.stack.Push("1")
|
vm.stack.Push("1")
|
||||||
} else {
|
} else {
|
||||||
vm.stack.Push("0")
|
vm.stack.Push("0")
|
||||||
}
|
}
|
||||||
case oGT:
|
case oGT:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// x > y
|
// x > y
|
||||||
if x.Cmp(y) > 0 {
|
if x.Cmp(y) > 0 {
|
||||||
vm.stack.Push("1")
|
vm.stack.Push("1")
|
||||||
} else {
|
} else {
|
||||||
vm.stack.Push("0")
|
vm.stack.Push("0")
|
||||||
}
|
}
|
||||||
case oGE:
|
case oGE:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// x >= y
|
// x >= y
|
||||||
if x.Cmp(y) > -1 {
|
if x.Cmp(y) > -1 {
|
||||||
vm.stack.Push("1")
|
vm.stack.Push("1")
|
||||||
} else {
|
} else {
|
||||||
vm.stack.Push("0")
|
vm.stack.Push("0")
|
||||||
}
|
}
|
||||||
case oNOT:
|
case oNOT:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
// x != y
|
// x != y
|
||||||
if x.Cmp(y) != 0 {
|
if x.Cmp(y) != 0 {
|
||||||
vm.stack.Push("1")
|
vm.stack.Push("1")
|
||||||
} else {
|
} else {
|
||||||
vm.stack.Push("0")
|
vm.stack.Push("0")
|
||||||
}
|
}
|
||||||
case oMYADDRESS:
|
case oMYADDRESS:
|
||||||
vm.stack.Push(string(tx.Hash()))
|
vm.stack.Push(string(tx.Hash()))
|
||||||
case oTXSENDER:
|
case oTXSENDER:
|
||||||
vm.stack.Push(string(tx.Sender()))
|
vm.stack.Push(string(tx.Sender()))
|
||||||
case oPUSH:
|
case oPUSH:
|
||||||
// Get the next entry and pushes the value on the stack
|
// Get the next entry and pushes the value on the stack
|
||||||
pc++
|
pc++
|
||||||
vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32))))
|
vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32))))
|
||||||
case oPOP:
|
case oPOP:
|
||||||
// Pop current value of the stack
|
// Pop current value of the stack
|
||||||
vm.stack.Pop()
|
vm.stack.Pop()
|
||||||
case oLOAD:
|
case oLOAD:
|
||||||
// Load instruction X on the stack
|
// Load instruction X on the stack
|
||||||
i, _ := strconv.Atoi(vm.stack.Pop())
|
i, _ := strconv.Atoi(vm.stack.Pop())
|
||||||
vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32))))
|
vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32))))
|
||||||
case oSTOP:
|
case oSTOP:
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.stack.Print()
|
vm.stack.Print()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user