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