From 3ee0461cb5b6e4a5e2d287180afbdb681805a662 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Oct 2014 10:59:17 +0100 Subject: Moved ethchain to chain --- block_pool.go | 16 +- chain/.gitignore | 12 ++ chain/asm.go | 45 ++++ chain/block.go | 419 ++++++++++++++++++++++++++++++++++++ chain/bloom.go | 47 ++++ chain/bloom9.go | 55 +++++ chain/bloom9_test.go | 17 ++ chain/bloom_test.go | 20 ++ chain/chain_manager.go | 289 +++++++++++++++++++++++++ chain/chain_manager_test.go | 1 + chain/dagger.go | 239 +++++++++++++++++++++ chain/dagger_test.go | 19 ++ chain/derive_sha.go | 20 ++ chain/error.go | 116 ++++++++++ chain/events.go | 10 + chain/fees.go | 7 + chain/filter.go | 197 +++++++++++++++++ chain/filter_test.go | 7 + chain/genesis.go | 53 +++++ chain/helper_test.go | 92 ++++++++ chain/state_manager.go | 451 +++++++++++++++++++++++++++++++++++++++ chain/state_transition.go | 264 +++++++++++++++++++++++ chain/transaction.go | 271 +++++++++++++++++++++++ chain/transaction_pool.go | 245 +++++++++++++++++++++ chain/transaction_test.go | 1 + chain/types.go | 312 +++++++++++++++++++++++++++ chain/vm_env.go | 39 ++++ cmd/mist/bindings.go | 4 +- cmd/mist/debugger.go | 4 +- cmd/mist/ext_app.go | 14 +- cmd/mist/gui.go | 20 +- cmd/mist/html_container.go | 4 +- cmd/mist/qml_container.go | 4 +- cmd/mist/ui_lib.go | 8 +- ethchain/.gitignore | 12 -- ethchain/asm.go | 45 ---- ethchain/block.go | 419 ------------------------------------ ethchain/bloom.go | 47 ---- ethchain/bloom9.go | 55 ----- ethchain/bloom9_test.go | 17 -- ethchain/bloom_test.go | 20 -- ethchain/chain_manager.go | 289 ------------------------- ethchain/chain_manager_test.go | 1 - ethchain/dagger.go | 239 --------------------- ethchain/dagger_test.go | 19 -- ethchain/derive_sha.go | 20 -- ethchain/error.go | 116 ---------- ethchain/events.go | 10 - ethchain/fees.go | 7 - ethchain/filter.go | 197 ----------------- ethchain/filter_test.go | 7 - ethchain/genesis.go | 53 ----- ethchain/helper_test.go | 92 -------- ethchain/state_manager.go | 451 --------------------------------------- ethchain/state_transition.go | 264 ----------------------- ethchain/transaction.go | 271 ----------------------- ethchain/transaction_pool.go | 245 --------------------- ethchain/transaction_test.go | 1 - ethchain/types.go | 312 --------------------------- ethchain/vm_env.go | 39 ---- ethereum.go | 32 +-- ethminer/miner.go | 30 +-- ethpipe/js_pipe.go | 14 +- ethpipe/js_types.go | 16 +- ethpipe/pipe.go | 20 +- ethpipe/vm_env.go | 6 +- javascript/javascript_runtime.go | 6 +- peer.go | 12 +- ui/filter.go | 12 +- ui/qt/filter.go | 6 +- utils/vm_env.go | 6 +- 71 files changed, 3365 insertions(+), 3365 deletions(-) create mode 100644 chain/.gitignore create mode 100644 chain/asm.go create mode 100644 chain/block.go create mode 100644 chain/bloom.go create mode 100644 chain/bloom9.go create mode 100644 chain/bloom9_test.go create mode 100644 chain/bloom_test.go create mode 100644 chain/chain_manager.go create mode 100644 chain/chain_manager_test.go create mode 100644 chain/dagger.go create mode 100644 chain/dagger_test.go create mode 100644 chain/derive_sha.go create mode 100644 chain/error.go create mode 100644 chain/events.go create mode 100644 chain/fees.go create mode 100644 chain/filter.go create mode 100644 chain/filter_test.go create mode 100644 chain/genesis.go create mode 100644 chain/helper_test.go create mode 100644 chain/state_manager.go create mode 100644 chain/state_transition.go create mode 100644 chain/transaction.go create mode 100644 chain/transaction_pool.go create mode 100644 chain/transaction_test.go create mode 100644 chain/types.go create mode 100644 chain/vm_env.go delete mode 100644 ethchain/.gitignore delete mode 100644 ethchain/asm.go delete mode 100644 ethchain/block.go delete mode 100644 ethchain/bloom.go delete mode 100644 ethchain/bloom9.go delete mode 100644 ethchain/bloom9_test.go delete mode 100644 ethchain/bloom_test.go delete mode 100644 ethchain/chain_manager.go delete mode 100644 ethchain/chain_manager_test.go delete mode 100644 ethchain/dagger.go delete mode 100644 ethchain/dagger_test.go delete mode 100644 ethchain/derive_sha.go delete mode 100644 ethchain/error.go delete mode 100644 ethchain/events.go delete mode 100644 ethchain/fees.go delete mode 100644 ethchain/filter.go delete mode 100644 ethchain/filter_test.go delete mode 100644 ethchain/genesis.go delete mode 100644 ethchain/helper_test.go delete mode 100644 ethchain/state_manager.go delete mode 100644 ethchain/state_transition.go delete mode 100644 ethchain/transaction.go delete mode 100644 ethchain/transaction_pool.go delete mode 100644 ethchain/transaction_test.go delete mode 100644 ethchain/types.go delete mode 100644 ethchain/vm_env.go diff --git a/block_pool.go b/block_pool.go index 334db9c1b..49fa07eb1 100644 --- a/block_pool.go +++ b/block_pool.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethwire" @@ -20,7 +20,7 @@ var poollogger = ethlog.NewLogger("BPOOL") type block struct { from *Peer peer *Peer - block *ethchain.Block + block *chain.Block reqAt time.Time requested int } @@ -73,7 +73,7 @@ func (self *BlockPool) HasCommonHash(hash []byte) bool { return self.eth.ChainManager().GetBlock(hash) != nil } -func (self *BlockPool) Blocks() (blocks ethchain.Blocks) { +func (self *BlockPool) Blocks() (blocks chain.Blocks) { for _, item := range self.pool { if item.block != nil { blocks = append(blocks, item.block) @@ -123,15 +123,15 @@ func (self *BlockPool) AddHash(hash []byte, peer *Peer) { } } -func (self *BlockPool) Add(b *ethchain.Block, peer *Peer) { +func (self *BlockPool) Add(b *chain.Block, peer *Peer) { self.addBlock(b, peer, false) } -func (self *BlockPool) AddNew(b *ethchain.Block, peer *Peer) { +func (self *BlockPool) AddNew(b *chain.Block, peer *Peer) { self.addBlock(b, peer, true) } -func (self *BlockPool) addBlock(b *ethchain.Block, peer *Peer, newBlock bool) { +func (self *BlockPool) addBlock(b *chain.Block, peer *Peer, newBlock bool) { self.mut.Lock() defer self.mut.Unlock() @@ -262,7 +262,7 @@ out: /* if !self.fetchingHashes { blocks := self.Blocks() - ethchain.BlockBy(ethchain.Number).Sort(blocks) + chain.BlockBy(chain.Number).Sort(blocks) if len(blocks) > 0 { if !self.eth.ChainManager().HasBlock(b.PrevHash) && self.pool[string(b.PrevHash)] == nil && !self.fetchingHashes { @@ -283,7 +283,7 @@ out: break out case <-procTimer.C: blocks := self.Blocks() - ethchain.BlockBy(ethchain.Number).Sort(blocks) + chain.BlockBy(chain.Number).Sort(blocks) // Find common block for i, block := range blocks { diff --git a/chain/.gitignore b/chain/.gitignore new file mode 100644 index 000000000..f725d58d1 --- /dev/null +++ b/chain/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/chain/asm.go b/chain/asm.go new file mode 100644 index 000000000..875321c1c --- /dev/null +++ b/chain/asm.go @@ -0,0 +1,45 @@ +package chain + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/ethutil" +) + +func Disassemble(script []byte) (asm []string) { + pc := new(big.Int) + for { + if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { + return + } + + // Get the memory location of pc + val := script[pc.Int64()] + // Get the opcode (it must be an opcode!) + op := OpCode(val) + + asm = append(asm, fmt.Sprintf("%04v: %v", pc, op)) + + switch op { + case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: + pc.Add(pc, ethutil.Big1) + a := int64(op) - int64(PUSH1) + 1 + if int(pc.Int64()+a) > len(script) { + return + } + + data := script[pc.Int64() : pc.Int64()+a] + if len(data) == 0 { + data = []byte{0} + } + asm = append(asm, fmt.Sprintf("%04v: 0x%x", pc, data)) + + pc.Add(pc, big.NewInt(a-1)) + } + + pc.Add(pc, ethutil.Big1) + } + + return asm +} diff --git a/chain/block.go b/chain/block.go new file mode 100644 index 000000000..17a19d391 --- /dev/null +++ b/chain/block.go @@ -0,0 +1,419 @@ +package chain + +import ( + "bytes" + "fmt" + "math/big" + "sort" + "time" + + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethtrie" + "github.com/ethereum/go-ethereum/ethutil" +) + +type BlockInfo struct { + Number uint64 + Hash []byte + Parent []byte + TD *big.Int +} + +func (bi *BlockInfo) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + bi.Number = decoder.Get(0).Uint() + bi.Hash = decoder.Get(1).Bytes() + bi.Parent = decoder.Get(2).Bytes() + bi.TD = decoder.Get(3).BigInt() +} + +func (bi *BlockInfo) RlpEncode() []byte { + return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD}) +} + +type Blocks []*Block + +func (self Blocks) AsSet() ethutil.UniqueSet { + set := make(ethutil.UniqueSet) + for _, block := range self { + set.Insert(block.Hash()) + } + + return set +} + +type BlockBy func(b1, b2 *Block) bool + +func (self BlockBy) Sort(blocks Blocks) { + bs := blockSorter{ + blocks: blocks, + by: self, + } + sort.Sort(bs) +} + +type blockSorter struct { + blocks Blocks + by func(b1, b2 *Block) bool +} + +func (self blockSorter) Len() int { return len(self.blocks) } +func (self blockSorter) Swap(i, j int) { + self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] +} +func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } + +func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } + +type Block struct { + // Hash to the previous block + PrevHash ethutil.Bytes + // Uncles of this block + Uncles Blocks + UncleSha []byte + // The coin base address + Coinbase []byte + // Block Trie state + //state *ethutil.Trie + state *ethstate.State + // Difficulty for the current block + Difficulty *big.Int + // Creation time + Time int64 + // The block number + Number *big.Int + // Minimum Gas Price + MinGasPrice *big.Int + // Gas limit + GasLimit *big.Int + // Gas used + GasUsed *big.Int + // Extra data + Extra string + // Block Nonce for verification + Nonce ethutil.Bytes + // List of transactions and/or contracts + transactions Transactions + receipts Receipts + TxSha, ReceiptSha []byte + LogsBloom []byte +} + +func NewBlockFromBytes(raw []byte) *Block { + block := &Block{} + block.RlpDecode(raw) + + return block +} + +// New block takes a raw encoded string +func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block { + block := &Block{} + block.RlpValueDecode(rlpValue) + + return block +} + +func CreateBlock(root interface{}, + prevHash []byte, + base []byte, + Difficulty *big.Int, + Nonce []byte, + extra string) *Block { + + block := &Block{ + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: nil, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), + } + block.SetUncles([]*Block{}) + + block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, root)) + + return block +} + +// Returns a hash of the block +func (block *Block) Hash() ethutil.Bytes { + return ethcrypto.Sha3(ethutil.NewValue(block.header()).Encode()) + //return ethcrypto.Sha3(block.Value().Encode()) +} + +func (block *Block) HashNoNonce() []byte { + return ethcrypto.Sha3(ethutil.Encode(block.miningHeader())) +} + +func (block *Block) State() *ethstate.State { + return block.state +} + +func (block *Block) Transactions() []*Transaction { + return block.transactions +} + +func (block *Block) CalcGasLimit(parent *Block) *big.Int { + if block.Number.Cmp(big.NewInt(0)) == 0 { + return ethutil.BigPow(10, 6) + } + + // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 + + previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit) + current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed), big.NewRat(6, 5)) + curInt := new(big.Int).Div(current.Num(), current.Denom()) + + result := new(big.Int).Add(previous, curInt) + result.Div(result, big.NewInt(1024)) + + min := big.NewInt(125000) + + return ethutil.BigMax(min, result) +} + +func (block *Block) BlockInfo() BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (self *Block) GetTransaction(hash []byte) *Transaction { + for _, tx := range self.transactions { + if bytes.Compare(tx.Hash(), hash) == 0 { + return tx + } + } + + return nil +} + +// Sync the block's state and contract respectively +func (block *Block) Sync() { + block.state.Sync() +} + +func (block *Block) Undo() { + // Sync the block state itself + block.state.Reset() +} + +/////// Block Encoding +func (block *Block) rlpReceipts() interface{} { + // Marshal the transactions of this block + encR := make([]interface{}, len(block.receipts)) + for i, r := range block.receipts { + // Cast it to a string (safe) + encR[i] = r.RlpData() + } + + return encR +} + +func (block *Block) rlpUncles() interface{} { + // Marshal the transactions of this block + uncles := make([]interface{}, len(block.Uncles)) + for i, uncle := range block.Uncles { + // Cast it to a string (safe) + uncles[i] = uncle.header() + } + + return uncles +} + +func (block *Block) SetUncles(uncles []*Block) { + block.Uncles = uncles + block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) +} + +func (self *Block) SetReceipts(receipts Receipts) { + self.receipts = receipts + self.ReceiptSha = DeriveSha(receipts) + self.LogsBloom = CreateBloom(self) +} + +func (self *Block) SetTransactions(txs Transactions) { + self.transactions = txs + self.TxSha = DeriveSha(txs) +} + +func (block *Block) Value() *ethutil.Value { + return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()}) +} + +func (block *Block) RlpEncode() []byte { + // Encode a slice interface which contains the header and the list of + // transactions. + return block.Value().Encode() +} + +func (block *Block) RlpDecode(data []byte) { + rlpValue := ethutil.NewValueFromBytes(data) + block.RlpValueDecode(rlpValue) +} + +func (block *Block) RlpValueDecode(decoder *ethutil.Value) { + block.setHeader(decoder.Get(0)) + + // Tx list might be empty if this is an uncle. Uncles only have their + // header set. + if decoder.Get(1).IsNil() == false { // Yes explicitness + //receipts := decoder.Get(1) + //block.receipts = make([]*Receipt, receipts.Len()) + txs := decoder.Get(1) + block.transactions = make(Transactions, txs.Len()) + for i := 0; i < txs.Len(); i++ { + block.transactions[i] = NewTransactionFromValue(txs.Get(i)) + //receipt := NewRecieptFromValue(receipts.Get(i)) + //block.transactions[i] = receipt.Tx + //block.receipts[i] = receipt + } + + } + + if decoder.Get(2).IsNil() == false { // Yes explicitness + uncles := decoder.Get(2) + block.Uncles = make([]*Block, uncles.Len()) + for i := 0; i < uncles.Len(); i++ { + block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i)) + } + } + +} + +func (self *Block) setHeader(header *ethutil.Value) { + self.PrevHash = header.Get(0).Bytes() + self.UncleSha = header.Get(1).Bytes() + self.Coinbase = header.Get(2).Bytes() + self.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) + self.TxSha = header.Get(4).Bytes() + self.ReceiptSha = header.Get(5).Bytes() + self.LogsBloom = header.Get(6).Bytes() + self.Difficulty = header.Get(7).BigInt() + self.Number = header.Get(8).BigInt() + self.MinGasPrice = header.Get(9).BigInt() + self.GasLimit = header.Get(10).BigInt() + self.GasUsed = header.Get(11).BigInt() + self.Time = int64(header.Get(12).BigInt().Uint64()) + self.Extra = header.Get(13).Str() + self.Nonce = header.Get(14).Bytes() +} + +func NewUncleBlockFromValue(header *ethutil.Value) *Block { + block := &Block{} + block.setHeader(header) + + return block +} + +func (block *Block) Trie() *ethtrie.Trie { + return block.state.Trie +} + +func (block *Block) GetRoot() interface{} { + return block.state.Trie.Root +} + +func (block *Block) Diff() *big.Int { + return block.Difficulty +} + +func (self *Block) Receipts() []*Receipt { + return self.receipts +} + +func (block *Block) miningHeader() []interface{} { + return []interface{}{ + // Sha of the previous block + block.PrevHash, + // Sha of uncles + block.UncleSha, + // Coinbase address + block.Coinbase, + // root state + block.state.Trie.Root, + // tx root + block.TxSha, + // Sha of tx + block.ReceiptSha, + // Bloom + block.LogsBloom, + // Current block Difficulty + block.Difficulty, + // The block number + block.Number, + // Block minimum gas price + block.MinGasPrice, + // Block upper gas bound + block.GasLimit, + // Block gas used + block.GasUsed, + // Time the block was found? + block.Time, + // Extra data + block.Extra, + } +} + +func (block *Block) header() []interface{} { + return append(block.miningHeader(), block.Nonce) +} + +func (block *Block) String() string { + return fmt.Sprintf(` + BLOCK(%x): Size: %v + PrevHash: %x + UncleSha: %x + Coinbase: %x + Root: %x + TxSha %x + ReceiptSha: %x + Bloom: %x + Difficulty: %v + Number: %v + MinGas: %v + MaxLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x + NumTx: %v +`, + block.Hash(), + block.Size(), + block.PrevHash, + block.UncleSha, + block.Coinbase, + block.state.Trie.Root, + block.TxSha, + block.ReceiptSha, + block.LogsBloom, + block.Difficulty, + block.Number, + block.MinGasPrice, + block.GasLimit, + block.GasUsed, + block.Time, + block.Extra, + block.Nonce, + len(block.transactions), + ) +} + +func (self *Block) Size() ethutil.StorageSize { + return ethutil.StorageSize(len(self.RlpEncode())) +} + +// Implement RlpEncodable +func (self *Block) RlpData() interface{} { + return self.Value().Val +} diff --git a/chain/bloom.go b/chain/bloom.go new file mode 100644 index 000000000..9d2cf439d --- /dev/null +++ b/chain/bloom.go @@ -0,0 +1,47 @@ +package chain + +type BloomFilter struct { + bin []byte +} + +func NewBloomFilter(bin []byte) *BloomFilter { + if bin == nil { + bin = make([]byte, 256) + } + + return &BloomFilter{ + bin: bin, + } +} + +func (self *BloomFilter) Set(addr []byte) { + if len(addr) < 8 { + chainlogger.Warnf("err: bloom set to small: %x\n", addr) + + return + } + + for _, i := range addr[len(addr)-8:] { + self.bin[i] = 1 + } +} + +func (self *BloomFilter) Search(addr []byte) bool { + if len(addr) < 8 { + chainlogger.Warnf("err: bloom search to small: %x\n", addr) + + return false + } + + for _, i := range addr[len(addr)-8:] { + if self.bin[i] == 0 { + return false + } + } + + return true +} + +func (self *BloomFilter) Bin() []byte { + return self.bin +} diff --git a/chain/bloom9.go b/chain/bloom9.go new file mode 100644 index 000000000..60cafdb4b --- /dev/null +++ b/chain/bloom9.go @@ -0,0 +1,55 @@ +package chain + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" +) + +func CreateBloom(block *Block) []byte { + bin := new(big.Int) + bin.Or(bin, bloom9(block.Coinbase)) + for _, receipt := range block.Receipts() { + bin.Or(bin, LogsBloom(receipt.logs)) + } + + return bin.Bytes() +} + +func LogsBloom(logs ethstate.Logs) *big.Int { + bin := new(big.Int) + for _, log := range logs { + data := [][]byte{log.Address} + for _, topic := range log.Topics { + data = append(data, topic) + } + + if log.Data != nil { + data = append(data, log.Data) + } + + for _, b := range data { + bin.Or(bin, bloom9(b)) + } + } + + return bin +} + +func bloom9(b []byte) *big.Int { + r := new(big.Int) + for _, i := range []int{0, 2, 4} { + t := big.NewInt(1) + r.Or(r, t.Lsh(t, uint(b[i+1])+256*(uint(b[i])&1))) + } + + return r +} + +func BloomLookup(bin, topic []byte) bool { + bloom := ethutil.BigD(bin) + cmp := bloom9(topic) + + return bloom.And(bloom, cmp).Cmp(cmp) == 0 +} diff --git a/chain/bloom9_test.go b/chain/bloom9_test.go new file mode 100644 index 000000000..b5a269504 --- /dev/null +++ b/chain/bloom9_test.go @@ -0,0 +1,17 @@ +package chain + +import ( + "testing" + + "github.com/ethereum/go-ethereum/vm" +) + +func TestBloom9(t *testing.T) { + testCase := []byte("testtest") + bin := LogsBloom([]vm.Log{vm.Log{testCase, [][]byte{[]byte("hellohello")}, nil}}).Bytes() + res := BloomLookup(bin, testCase) + + if !res { + t.Errorf("Bloom lookup failed") + } +} diff --git a/chain/bloom_test.go b/chain/bloom_test.go new file mode 100644 index 000000000..13c0d94e4 --- /dev/null +++ b/chain/bloom_test.go @@ -0,0 +1,20 @@ +package chain + +import "testing" + +func TestBloomFilter(t *testing.T) { + bf := NewBloomFilter(nil) + + a := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} + bf.Set(a) + + b := []byte{10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + + if bf.Search(a) == false { + t.Error("Expected 'a' to yield true using a bloom filter") + } + + if bf.Search(b) { + t.Error("Expected 'b' not to field trie using a bloom filter") + } +} diff --git a/chain/chain_manager.go b/chain/chain_manager.go new file mode 100644 index 000000000..83ae21dcc --- /dev/null +++ b/chain/chain_manager.go @@ -0,0 +1,289 @@ +package chain + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/ethutil" +) + +var chainlogger = ethlog.NewLogger("CHAIN") + +type ChainManager struct { + Ethereum EthManager + // The famous, the fabulous Mister GENESIIIIIIS (block) + genesisBlock *Block + // Last known total difficulty + TD *big.Int + + LastBlockNumber uint64 + + CurrentBlock *Block + LastBlockHash []byte +} + +func NewChainManager(ethereum EthManager) *ChainManager { + bc := &ChainManager{} + bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) + bc.Ethereum = ethereum + + bc.setLastBlock() + + return bc +} + +func (bc *ChainManager) Genesis() *Block { + return bc.genesisBlock +} + +func (bc *ChainManager) NewBlock(coinbase []byte) *Block { + var root interface{} + hash := ZeroHash256 + + if bc.CurrentBlock != nil { + root = bc.CurrentBlock.state.Trie.Root + hash = bc.LastBlockHash + } + + block := CreateBlock( + root, + hash, + coinbase, + ethutil.BigPow(2, 32), + nil, + "") + + block.MinGasPrice = big.NewInt(10000000000000) + + parent := bc.CurrentBlock + if parent != nil { + block.Difficulty = CalcDifficulty(block, parent) + block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) + block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) + + } + + return block +} + +func CalcDifficulty(block, parent *Block) *big.Int { + diff := new(big.Int) + + adjust := new(big.Int).Rsh(parent.Difficulty, 10) + if block.Time >= parent.Time+5 { + diff.Sub(parent.Difficulty, adjust) + } else { + diff.Add(parent.Difficulty, adjust) + } + + return diff +} + +func (bc *ChainManager) Reset() { + AddTestNetFunds(bc.genesisBlock) + + bc.genesisBlock.state.Trie.Sync() + // Prepare the genesis block + bc.Add(bc.genesisBlock) + bc.CurrentBlock = bc.genesisBlock + + bc.SetTotalDifficulty(ethutil.Big("0")) + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) +} + +func (bc *ChainManager) HasBlock(hash []byte) bool { + data, _ := ethutil.Config.Db.Get(hash) + return len(data) != 0 +} + +// TODO: At one point we might want to save a block by prevHash in the db to optimise this... +func (bc *ChainManager) HasBlockWithPrevHash(hash []byte) bool { + block := bc.CurrentBlock + + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(hash, block.PrevHash) == 0 { + return true + } + } + return false +} + +func (bc *ChainManager) CalculateBlockTD(block *Block) *big.Int { + blockDiff := new(big.Int) + + for _, uncle := range block.Uncles { + blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty) + } + blockDiff = blockDiff.Add(blockDiff, block.Difficulty) + + return blockDiff +} + +func (bc *ChainManager) GenesisBlock() *Block { + return bc.genesisBlock +} + +func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { + block := self.GetBlock(hash) + if block == nil { + return + } + + // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list) + for i := uint64(0); i < max; i++ { + chain = append(chain, block.Hash()) + + if block.Number.Cmp(ethutil.Big0) <= 0 { + break + } + + block = self.GetBlock(block.PrevHash) + } + + return +} + +func AddTestNetFunds(block *Block) { + for _, addr := range []string{ + "51ba59315b3a95761d0863b05ccc7a7f54703d99", + "e4157b34ea9615cfbde6b4fda419828124b70c78", + "b9c015918bdaba24b4ff057a92a3873d6eb201be", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", + } { + codedAddr := ethutil.Hex2Bytes(addr) + account := block.state.GetAccount(codedAddr) + account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) + block.state.UpdateStateObject(account) + } +} + +func (bc *ChainManager) setLastBlock() { + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) + if len(data) != 0 { + // Prep genesis + AddTestNetFunds(bc.genesisBlock) + + block := NewBlockFromBytes(data) + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + bc.LastBlockNumber = block.Number.Uint64() + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) + } else { + bc.Reset() + } + + chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) +} + +func (bc *ChainManager) SetTotalDifficulty(td *big.Int) { + ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) + bc.TD = td +} + +// Add a block to the chain and record addition information +func (bc *ChainManager) Add(block *Block) { + bc.writeBlockInfo(block) + // Prepare the genesis block + + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + + encodedBlock := block.RlpEncode() + ethutil.Config.Db.Put(block.Hash(), encodedBlock) + ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) +} + +func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) { + parent := self.GetBlock(block.PrevHash) + if parent == nil { + return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) + } + + parentTd := parent.BlockInfo().TD + + uncleDiff := new(big.Int) + for _, uncle := range block.Uncles { + uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) + } + + td := new(big.Int) + td = td.Add(parentTd, uncleDiff) + td = td.Add(td, block.Difficulty) + + return td, nil +} + +func (bc *ChainManager) GetBlock(hash []byte) *Block { + data, _ := ethutil.Config.Db.Get(hash) + if len(data) == 0 { + return nil + } + + return NewBlockFromBytes(data) +} + +func (self *ChainManager) GetBlockByNumber(num uint64) *Block { + block := self.CurrentBlock + for ; block != nil; block = self.GetBlock(block.PrevHash) { + if block.Number.Uint64() == num { + break + } + } + + if block != nil && block.Number.Uint64() == 0 && num != 0 { + return nil + } + + return block +} + +func (self *ChainManager) GetBlockBack(num uint64) *Block { + block := self.CurrentBlock + + for ; num != 0 && block != nil; num-- { + block = self.GetBlock(block.PrevHash) + } + + return block +} + +func (bc *ChainManager) BlockInfoByHash(hash []byte) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (bc *ChainManager) BlockInfo(block *Block) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +// Unexported method for writing extra non-essential block info to the db +func (bc *ChainManager) writeBlockInfo(block *Block) { + bc.LastBlockNumber++ + bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD} + + // For now we use the block hash with the words "info" appended as key + ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode()) +} + +func (bc *ChainManager) Stop() { + if bc.CurrentBlock != nil { + chainlogger.Infoln("Stopped") + } +} diff --git a/chain/chain_manager_test.go b/chain/chain_manager_test.go new file mode 100644 index 000000000..fef1d2010 --- /dev/null +++ b/chain/chain_manager_test.go @@ -0,0 +1 @@ +package chain diff --git a/chain/dagger.go b/chain/dagger.go new file mode 100644 index 000000000..bb6b136f6 --- /dev/null +++ b/chain/dagger.go @@ -0,0 +1,239 @@ +package chain + +import ( + "hash" + "math/big" + "math/rand" + "time" + + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/obscuren/sha3" +) + +var powlogger = ethlog.NewLogger("POW") + +type PoW interface { + Search(block *Block, stop <-chan struct{}) []byte + Verify(hash []byte, diff *big.Int, nonce []byte) bool + GetHashrate() int64 + Turbo(bool) +} + +type EasyPow struct { + hash *big.Int + HashRate int64 + turbo bool +} + +func (pow *EasyPow) GetHashrate() int64 { + return pow.HashRate +} + +func (pow *EasyPow) Turbo(on bool) { + pow.turbo = on +} + +func (pow *EasyPow) Search(block *Block, stop <-chan struct{}) []byte { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + hash := block.HashNoNonce() + diff := block.Difficulty + i := int64(0) + start := time.Now().UnixNano() + t := time.Now() + + for { + select { + case <-stop: + powlogger.Infoln("Breaking from mining") + return nil + default: + i++ + + if time.Since(t) > (1 * time.Second) { + elapsed := time.Now().UnixNano() - start + hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 + pow.HashRate = int64(hashes) + powlogger.Infoln("Hashing @", int64(pow.HashRate), "khash") + + t = time.Now() + } + + sha := ethcrypto.Sha3(big.NewInt(r.Int63()).Bytes()) + if pow.Verify(hash, diff, sha) { + return sha + } + } + + if !pow.turbo { + time.Sleep(20 * time.Microsecond) + } + } + + return nil +} + +func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool { + sha := sha3.NewKeccak256() + + d := append(hash, nonce...) + sha.Write(d) + + v := ethutil.BigPow(2, 256) + ret := new(big.Int).Div(v, diff) + + res := new(big.Int) + res.SetBytes(sha.Sum(nil)) + + return res.Cmp(ret) == -1 +} + +func (pow *EasyPow) SetHash(hash *big.Int) { +} + +type Dagger struct { + 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())) + + for i := 0; i < 1000; i++ { + rnd := r.Int63() + + res := dag.Eval(big.NewInt(rnd)) + powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj) + if res.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 + } + } + + 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 + + dag.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + Found = false + resChan := make(chan int64, 3) + var res int64 + + 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 + } + } + + return big.NewInt(res) +} + +func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool { + dag.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + return dag.Eval(nonce).Cmp(obj) < 0 +} + +func DaggerVerify(hash, diff, nonce *big.Int) bool { + dagger := &Dagger{} + dagger.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + 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 +} + +func Sum(sha hash.Hash) []byte { + //in := make([]byte, 32) + return sha.Sum(nil) +} + +func (dag *Dagger) Eval(N *big.Int) *big.Int { + pow := ethutil.BigPow(2, 26) + dag.xn = pow.Div(N, pow) + + sha := sha3.NewKeccak256() + sha.Reset() + ret := 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()) + + b.SetBytes(Sum(d)) + pk := (b.Uint64() & 0x1ffffff) + + sha.Write(dag.Node(9, pk).Bytes()) + } + + return ret.SetBytes(Sum(sha)) +} diff --git a/chain/dagger_test.go b/chain/dagger_test.go new file mode 100644 index 000000000..b40cd9742 --- /dev/null +++ b/chain/dagger_test.go @@ -0,0 +1,19 @@ +package chain + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/ethutil" +) + +func BenchmarkDaggerSearch(b *testing.B) { + hash := big.NewInt(0) + diff := ethutil.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) +} diff --git a/chain/derive_sha.go b/chain/derive_sha.go new file mode 100644 index 000000000..92db90d95 --- /dev/null +++ b/chain/derive_sha.go @@ -0,0 +1,20 @@ +package chain + +import ( + "github.com/ethereum/go-ethereum/ethtrie" + "github.com/ethereum/go-ethereum/ethutil" +) + +type DerivableList interface { + Len() int + GetRlp(i int) []byte +} + +func DeriveSha(list DerivableList) []byte { + trie := ethtrie.New(ethutil.Config.Db, "") + for i := 0; i < list.Len(); i++ { + trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i))) + } + + return trie.GetRoot() +} diff --git a/chain/error.go b/chain/error.go new file mode 100644 index 000000000..204b8b873 --- /dev/null +++ b/chain/error.go @@ -0,0 +1,116 @@ +package chain + +import ( + "fmt" + "math/big" +) + +// Parent error. In case a parent is unknown this error will be thrown +// by the block manager +type ParentErr struct { + Message string +} + +func (err *ParentErr) Error() string { + return err.Message +} + +func ParentError(hash []byte) error { + return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)} +} + +func IsParentErr(err error) bool { + _, ok := err.(*ParentErr) + + return ok +} + +type UncleErr struct { + Message string +} + +func (err *UncleErr) Error() string { + return err.Message +} + +func UncleError(str string) error { + return &UncleErr{Message: str} +} + +func IsUncleErr(err error) bool { + _, ok := err.(*UncleErr) + + return ok +} + +// Block validation error. If any validation fails, this error will be thrown +type ValidationErr struct { + Message string +} + +func (err *ValidationErr) Error() string { + return err.Message +} + +func ValidationError(format string, v ...interface{}) *ValidationErr { + return &ValidationErr{Message: fmt.Sprintf(format, v...)} +} + +func IsValidationErr(err error) bool { + _, ok := err.(*ValidationErr) + + return ok +} + +type GasLimitErr struct { + Message string + Is, Max *big.Int +} + +func IsGasLimitErr(err error) bool { + _, ok := err.(*GasLimitErr) + + return ok +} +func (err *GasLimitErr) Error() string { + return err.Message +} +func GasLimitError(is, max *big.Int) *GasLimitErr { + return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max} +} + +type NonceErr struct { + Message string + Is, Exp uint64 +} + +func (err *NonceErr) Error() string { + return err.Message +} + +func NonceError(is, exp uint64) *NonceErr { + return &NonceErr{Message: fmt.Sprintf("Nonce err. Is %d, expected %d", is, exp), Is: is, Exp: exp} +} + +func IsNonceErr(err error) bool { + _, ok := err.(*NonceErr) + + return ok +} + +type OutOfGasErr struct { + Message string +} + +func OutOfGasError() *OutOfGasErr { + return &OutOfGasErr{Message: "Out of gas"} +} +func (self *OutOfGasErr) Error() string { + return self.Message +} + +func IsOutOfGasErr(err error) bool { + _, ok := err.(*OutOfGasErr) + + return ok +} diff --git a/chain/events.go b/chain/events.go new file mode 100644 index 000000000..2703e955d --- /dev/null +++ b/chain/events.go @@ -0,0 +1,10 @@ +package chain + +// TxPreEvent is posted when a transaction enters the transaction pool. +type TxPreEvent struct{ Tx *Transaction } + +// TxPostEvent is posted when a transaction has been processed. +type TxPostEvent struct{ Tx *Transaction } + +// NewBlockEvent is posted when a block has been imported. +type NewBlockEvent struct{ Block *Block } diff --git a/chain/fees.go b/chain/fees.go new file mode 100644 index 000000000..4df6d365d --- /dev/null +++ b/chain/fees.go @@ -0,0 +1,7 @@ +package chain + +import ( + "math/big" +) + +var BlockReward *big.Int = big.NewInt(1.5e+18) diff --git a/chain/filter.go b/chain/filter.go new file mode 100644 index 000000000..2aecb4f58 --- /dev/null +++ b/chain/filter.go @@ -0,0 +1,197 @@ +package chain + +import ( + "bytes" + "math" + + "github.com/ethereum/go-ethereum/ethstate" +) + +type AccountChange struct { + Address, StateAddress []byte +} + +// Filtering interface +type Filter struct { + eth EthManager + earliest int64 + latest int64 + skip int + from, to [][]byte + max int + + Altered []AccountChange + + BlockCallback func(*Block) + MessageCallback func(ethstate.Messages) +} + +// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block +// is interesting or not. +func NewFilter(eth EthManager) *Filter { + return &Filter{eth: eth} +} + +func (self *Filter) AddAltered(address, stateAddress []byte) { + self.Altered = append(self.Altered, AccountChange{address, stateAddress}) +} + +// Set the earliest and latest block for filtering. +// -1 = latest block (i.e., the current block) +// hash = particular hash from-to +func (self *Filter) SetEarliestBlock(earliest int64) { + self.earliest = earliest +} + +func (self *Filter) SetLatestBlock(latest int64) { + self.latest = latest +} + +func (self *Filter) SetFrom(addr [][]byte) { + self.from = addr +} + +func (self *Filter) AddFrom(addr []byte) { + self.from = append(self.from, addr) +} + +func (self *Filter) SetTo(addr [][]byte) { + self.to = addr +} + +func (self *Filter) AddTo(addr []byte) { + self.to = append(self.to, addr) +} + +func (self *Filter) SetMax(max int) { + self.max = max +} + +func (self *Filter) SetSkip(skip int) { + self.skip = skip +} + +// Run filters messages with the current parameters set +func (self *Filter) Find() []*ethstate.Message { + var earliestBlockNo uint64 = uint64(self.earliest) + if self.earliest == -1 { + earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() + } + var latestBlockNo uint64 = uint64(self.latest) + if self.latest == -1 { + latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() + } + + var ( + messages []*ethstate.Message + block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo) + quit bool + ) + for i := 0; !quit && block != nil; i++ { + // Quit on latest + switch { + case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0: + quit = true + case self.max <= len(messages): + break + } + + // Use bloom filtering to see if this block is interesting given the + // current parameters + if self.bloomFilter(block) { + // Get the messages of the block + msgs, err := self.eth.StateManager().GetMessages(block) + if err != nil { + chainlogger.Warnln("err: filter get messages ", err) + + break + } + + messages = append(messages, self.FilterMessages(msgs)...) + } + + block = self.eth.ChainManager().GetBlock(block.PrevHash) + } + + skip := int(math.Min(float64(len(messages)), float64(self.skip))) + + return messages[skip:] +} + +func includes(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true + } + } + + return +} + +func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message { + var messages []*ethstate.Message + + // Filter the messages for interesting stuff + for _, message := range msgs { + if len(self.to) > 0 && !includes(self.to, message.To) { + continue + } + + if len(self.from) > 0 && !includes(self.from, message.From) { + continue + } + + var match bool + if len(self.Altered) == 0 { + match = true + } + + for _, accountChange := range self.Altered { + if len(accountChange.Address) > 0 && bytes.Compare(message.To, accountChange.Address) != 0 { + continue + } + + if len(accountChange.StateAddress) > 0 && !includes(message.ChangedAddresses, accountChange.StateAddress) { + continue + } + + match = true + break + } + + if !match { + continue + } + + messages = append(messages, message) + } + + return messages +} + +func (self *Filter) bloomFilter(block *Block) bool { + var fromIncluded, toIncluded bool + if len(self.from) > 0 { + for _, from := range self.from { + if BloomLookup(block.LogsBloom, from) { + fromIncluded = true + break + } + } + } else { + fromIncluded = true + } + + if len(self.to) > 0 { + for _, to := range self.to { + if BloomLookup(block.LogsBloom, to) { + toIncluded = true + break + } + } + } else { + toIncluded = true + } + + return fromIncluded && toIncluded +} diff --git a/chain/filter_test.go b/chain/filter_test.go new file mode 100644 index 000000000..abfbf4b87 --- /dev/null +++ b/chain/filter_test.go @@ -0,0 +1,7 @@ +package chain + +import "testing" + +func TestFilter(t *testing.T) { + NewFilter(NewTestManager()) +} diff --git a/chain/genesis.go b/chain/genesis.go new file mode 100644 index 000000000..2f3b1919b --- /dev/null +++ b/chain/genesis.go @@ -0,0 +1,53 @@ +package chain + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethutil" +) + +/* + * This is the special genesis block. + */ + +var ZeroHash256 = make([]byte, 32) +var ZeroHash160 = make([]byte, 20) +var ZeroHash512 = make([]byte, 64) +var EmptyShaList = ethcrypto.Sha3(ethutil.Encode([]interface{}{})) + +var GenesisHeader = []interface{}{ + // Previous hash (none) + ZeroHash256, + // Empty uncles + EmptyShaList, + // Coinbase + ZeroHash160, + // Root state + EmptyShaList, + // tx sha + EmptyShaList, + // receipt list + EmptyShaList, + // bloom + ZeroHash512, + // Difficulty + //ethutil.BigPow(2, 22), + big.NewInt(131072), + // Number + ethutil.Big0, + // Block minimum gas price + ethutil.Big0, + // Block upper gas bound + big.NewInt(1000000), + // Block gas used + ethutil.Big0, + // Time + ethutil.Big0, + // Extra + nil, + // Nonce + ethcrypto.Sha3(big.NewInt(42).Bytes()), +} + +var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} diff --git a/chain/helper_test.go b/chain/helper_test.go new file mode 100644 index 000000000..59d1c4cca --- /dev/null +++ b/chain/helper_test.go @@ -0,0 +1,92 @@ +package chain + +import ( + "container/list" + "fmt" + + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/ethwire" + "github.com/ethereum/go-ethereum/event" +) + +// Implement our EthTest Manager +type TestManager struct { + stateManager *StateManager + eventMux *event.TypeMux + + db ethutil.Database + txPool *TxPool + blockChain *ChainManager + Blocks []*Block +} + +func (s *TestManager) IsListening() bool { + return false +} + +func (s *TestManager) IsMining() bool { + return false +} + +func (s *TestManager) PeerCount() int { + return 0 +} + +func (s *TestManager) Peers() *list.List { + return list.New() +} + +func (s *TestManager) ChainManager() *ChainManager { + return s.blockChain +} + +func (tm *TestManager) TxPool() *TxPool { + return tm.txPool +} + +func (tm *TestManager) StateManager() *StateManager { + return tm.stateManager +} + +func (tm *TestManager) EventMux() *event.TypeMux { + return tm.eventMux +} +func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { + fmt.Println("Broadcast not implemented") +} + +func (tm *TestManager) ClientIdentity() ethwire.ClientIdentity { + return nil +} +func (tm *TestManager) KeyManager() *ethcrypto.KeyManager { + return nil +} + +func (tm *TestManager) Db() ethutil.Database { + return tm.db +} + +func NewTestManager() *TestManager { + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH") + + db, err := ethdb.NewMemDatabase() + if err != nil { + fmt.Println("Could not create mem-db, failing") + return nil + } + ethutil.Config.Db = db + + testManager := &TestManager{} + testManager.eventMux = new(event.TypeMux) + testManager.db = db + testManager.txPool = NewTxPool(testManager) + testManager.blockChain = NewChainManager(testManager) + testManager.stateManager = NewStateManager(testManager) + + // Start the tx pool + testManager.txPool.Start() + + return testManager +} diff --git a/chain/state_manager.go b/chain/state_manager.go new file mode 100644 index 000000000..f78eb925a --- /dev/null +++ b/chain/state_manager.go @@ -0,0 +1,451 @@ +package chain + +import ( + "bytes" + "container/list" + "fmt" + "math/big" + "os" + "sync" + "time" + + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/ethwire" + "github.com/ethereum/go-ethereum/event" +) + +var statelogger = ethlog.NewLogger("BLOCK") + +type Peer interface { + Inbound() bool + LastSend() time.Time + LastPong() int64 + Host() []byte + Port() uint16 + Version() string + PingTime() string + Connected() *int32 + Caps() *ethutil.Value +} + +type EthManager interface { + StateManager() *StateManager + ChainManager() *ChainManager + TxPool() *TxPool + Broadcast(msgType ethwire.MsgType, data []interface{}) + PeerCount() int + IsMining() bool + IsListening() bool + Peers() *list.List + KeyManager() *ethcrypto.KeyManager + ClientIdentity() ethwire.ClientIdentity + Db() ethutil.Database + EventMux() *event.TypeMux +} + +type StateManager struct { + // Mutex for locking the block processor. Blocks can only be handled one at a time + mutex sync.Mutex + // Canonical block chain + bc *ChainManager + // non-persistent key/value memory storage + mem map[string]*big.Int + // Proof of work used for validating + Pow PoW + // The ethereum manager interface + eth EthManager + // The managed states + // Transiently state. The trans state isn't ever saved, validated and + // it could be used for setting account nonces without effecting + // the main states. + transState *ethstate.State + // Mining state. The mining state is used purely and solely by the mining + // operation. + miningState *ethstate.State + + // The last attempted block is mainly used for debugging purposes + // This does not have to be a valid block and will be set during + // 'Process' & canonical validation. + lastAttemptedBlock *Block + + events event.Subscription +} + +func NewStateManager(ethereum EthManager) *StateManager { + sm := &StateManager{ + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + eth: ethereum, + bc: ethereum.ChainManager(), + } + sm.transState = ethereum.ChainManager().CurrentBlock.State().Copy() + sm.miningState = ethereum.ChainManager().CurrentBlock.State().Copy() + + return sm +} + +func (self *StateManager) Start() { + statelogger.Debugln("Starting state manager") + self.events = self.eth.EventMux().Subscribe(Blocks(nil)) + go self.updateThread() +} + +func (self *StateManager) Stop() { + statelogger.Debugln("Stopping state manager") + self.events.Unsubscribe() +} + +func (self *StateManager) updateThread() { + for ev := range self.events.Chan() { + for _, block := range ev.(Blocks) { + err := self.Process(block) + if err != nil { + statelogger.Infoln(err) + statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) + statelogger.Debugln(block) + break + } + } + } +} + +func (sm *StateManager) CurrentState() *ethstate.State { + return sm.eth.ChainManager().CurrentBlock.State() +} + +func (sm *StateManager) TransState() *ethstate.State { + return sm.transState +} + +func (sm *StateManager) MiningState() *ethstate.State { + return sm.miningState +} + +func (sm *StateManager) NewMiningState() *ethstate.State { + sm.miningState = sm.eth.ChainManager().CurrentBlock.State().Copy() + + return sm.miningState +} + +func (sm *StateManager) ChainManager() *ChainManager { + return sm.bc +} + +func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, state *ethstate.State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, Transactions, error) { + var ( + receipts Receipts + handled, unhandled Transactions + erroneous Transactions + totalUsedGas = big.NewInt(0) + err error + ) + +done: + for i, tx := range txs { + // If we are mining this block and validating we want to set the logs back to 0 + state.EmptyLogs() + + txGas := new(big.Int).Set(tx.Gas) + + cb := state.GetStateObject(coinbase.Address()) + st := NewStateTransition(cb, tx, state, block) + err = st.TransitionState() + if err != nil { + statelogger.Infoln(err) + switch { + case IsNonceErr(err): + err = nil // ignore error + continue + case IsGasLimitErr(err): + unhandled = txs[i:] + + break done + default: + statelogger.Infoln(err) + erroneous = append(erroneous, tx) + err = nil + continue + //return nil, nil, nil, err + } + } + + // Update the state with pending changes + state.Update() + + txGas.Sub(txGas, st.gas) + cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) + //receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(state.Logs()).Bytes(), state.Logs()} + + if i < len(block.Receipts()) { + original := block.Receipts()[i] + if !original.Cmp(receipt) { + if ethutil.Config.Diff { + os.Exit(1) + } + + err := fmt.Errorf("#%d receipt failed (r) %v ~ %x <=> (c) %v ~ %x (%x...)", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], tx.Hash()[0:4]) + + return nil, nil, nil, nil, err + } + } + + // Notify all subscribers + go self.eth.EventMux().Post(TxPostEvent{tx}) + + receipts = append(receipts, receipt) + handled = append(handled, tx) + + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { + state.CreateOutputForDiff() + } + } + + parent.GasUsed = totalUsedGas + + return receipts, handled, unhandled, erroneous, err +} + +func (sm *StateManager) Process(block *Block) (err error) { + // Processing a blocks may never happen simultaneously + sm.mutex.Lock() + defer sm.mutex.Unlock() + + if sm.bc.HasBlock(block.Hash()) { + return nil + } + + if !sm.bc.HasBlock(block.PrevHash) { + return ParentError(block.PrevHash) + } + + sm.lastAttemptedBlock = block + + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State() + ) + + // Defer the Undo on the Trie. If the block processing happened + // we don't want to undo but since undo only happens on dirty + // nodes this won't happen because Commit would have been called + // before that. + defer state.Reset() + + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { + fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) + } + + txSha := DeriveSha(block.transactions) + if bytes.Compare(txSha, block.TxSha) != 0 { + return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.TxSha, txSha) + } + + receipts, err := sm.ApplyDiff(state, parent, block) + if err != nil { + return err + } + + receiptSha := DeriveSha(receipts) + if bytes.Compare(receiptSha, block.ReceiptSha) != 0 { + return fmt.Errorf("Error validating receipt sha. Received %x, got %x", block.ReceiptSha, receiptSha) + } + + // Block validation + if err = sm.ValidateBlock(block); err != nil { + statelogger.Errorln("Error validating block:", err) + return err + } + + if err = sm.AccumelateRewards(state, block, parent); err != nil { + statelogger.Errorln("Error accumulating reward", err) + return err + } + + state.Update() + + if !block.State().Cmp(state) { + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) + return + } + + // Calculate the new total difficulty and sync back to the db + if sm.CalculateTD(block) { + // Sync the current block's state to the database and cancelling out the deferred Undo + state.Sync() + + // Add the block to the chain + sm.bc.Add(block) + + // TODO at this point we should also insert LOGS in to a database + + sm.transState = state.Copy() + + statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) + + state.Manifest().Reset() + + sm.eth.TxPool().RemoveSet(block.Transactions()) + } else { + statelogger.Errorln("total diff failed") + } + + return nil +} + +func (sm *StateManager) ApplyDiff(state *ethstate.State, parent, block *Block) (receipts Receipts, err error) { + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.SetGasPool(block.CalcGasLimit(parent)) + + // Process the transactions on to current block + receipts, _, _, _, err = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + if err != nil { + return nil, err + } + + return receipts, nil +} + +func (sm *StateManager) CalculateTD(block *Block) bool { + uncleDiff := new(big.Int) + for _, uncle := range block.Uncles { + uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) + } + + // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty + td := new(big.Int) + td = td.Add(sm.bc.TD, uncleDiff) + td = td.Add(td, block.Difficulty) + + // The new TD will only be accepted if the new difficulty is + // is greater than the previous. + if td.Cmp(sm.bc.TD) > 0 { + // Set the new total difficulty back to the block chain + sm.bc.SetTotalDifficulty(td) + + return true + } + + return false +} + +// Validates the current block. Returns an error if the block was invalid, +// an uncle or anything that isn't on the current block chain. +// Validation validates easy over difficult (dagger takes longer time = difficult) +func (sm *StateManager) ValidateBlock(block *Block) error { + // Check each uncle's previous hash. In order for it to be valid + // is if it has the same block hash as the current + parent := sm.bc.GetBlock(block.PrevHash) + /* + for _, uncle := range block.Uncles { + if bytes.Compare(uncle.PrevHash,parent.PrevHash) != 0 { + return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x",parent.PrevHash, uncle.PrevHash) + } + } + */ + + expd := CalcDifficulty(block, parent) + if expd.Cmp(block.Difficulty) < 0 { + return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) + } + + diff := block.Time - parent.Time + if diff < 0 { + return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time) + } + + /* XXX + // New blocks must be within the 15 minute range of the last block. + if diff > int64(15*time.Minute) { + return ValidationError("Block is too far in the future of last block (> 15 minutes)") + } + */ + + // Verify the nonce of the block. Return an error if it's not valid + if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { + return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce)) + } + + return nil +} + +func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error { + reward := new(big.Int).Set(BlockReward) + + knownUncles := ethutil.Set(parent.Uncles) + nonces := ethutil.NewSet(block.Nonce) + for _, uncle := range block.Uncles { + if nonces.Include(uncle.Nonce) { + // Error not unique + return UncleError("Uncle not unique") + } + + uncleParent := sm.bc.GetBlock(uncle.PrevHash) + if uncleParent == nil { + return UncleError("Uncle's parent unknown") + } + + if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 { + return UncleError("Uncle too old") + } + + if knownUncles.Include(uncle.Hash()) { + return UncleError("Uncle in chain") + } + + nonces.Insert(uncle.Nonce) + + r := new(big.Int) + r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) + + uncleAccount := state.GetAccount(uncle.Coinbase) + uncleAccount.AddAmount(r) + + reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) + } + + // Get the account associated with the coinbase + account := state.GetAccount(block.Coinbase) + // Reward amount of ether to the coinbase address + account.AddAmount(reward) + + return nil +} + +// Manifest will handle both creating notifications and generating bloom bin data +func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { + bloomf := NewBloomFilter(nil) + + for _, msg := range state.Manifest().Messages { + bloomf.Set(msg.To) + bloomf.Set(msg.From) + } + + sm.eth.EventMux().Post(state.Manifest().Messages) + + return bloomf +} + +func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, err error) { + if !sm.bc.HasBlock(block.PrevHash) { + return nil, ParentError(block.PrevHash) + } + + sm.lastAttemptedBlock = block + + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State().Copy() + ) + + defer state.Reset() + + sm.ApplyDiff(state, parent, block) + + sm.AccumelateRewards(state, block, parent) + + return state.Manifest().Messages, nil +} diff --git a/chain/state_transition.go b/chain/state_transition.go new file mode 100644 index 000000000..4c62633c5 --- /dev/null +++ b/chain/state_transition.go @@ -0,0 +1,264 @@ +package chain + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/vm" +) + +/* + * The State transitioning model + * + * A state transition is a change made when a transaction is applied to the current world state + * The state transitioning model does all all the necessary work to work out a valid new state root. + * 1) Nonce handling + * 2) Pre pay / buy gas of the coinbase (miner) + * 3) Create a new state object if the recipient is \0*32 + * 4) Value transfer + * == If contract creation == + * 4a) Attempt to run transaction data + * 4b) If valid, use result as code for the new state object + * == end == + * 5) Run Script section + * 6) Derive new state root + */ +type StateTransition struct { + coinbase, receiver []byte + tx *Transaction + gas, gasPrice *big.Int + value *big.Int + data []byte + state *ethstate.State + block *Block + + cb, rec, sen *ethstate.StateObject +} + +func NewStateTransition(coinbase *ethstate.StateObject, tx *Transaction, state *ethstate.State, block *Block) *StateTransition { + return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} +} + +func (self *StateTransition) Coinbase() *ethstate.StateObject { + if self.cb != nil { + return self.cb + } + + self.cb = self.state.GetOrNewStateObject(self.coinbase) + return self.cb +} +func (self *StateTransition) Sender() *ethstate.StateObject { + if self.sen != nil { + return self.sen + } + + self.sen = self.state.GetOrNewStateObject(self.tx.Sender()) + + return self.sen +} +func (self *StateTransition) Receiver() *ethstate.StateObject { + if self.tx != nil && self.tx.CreatesContract() { + return nil + } + + if self.rec != nil { + return self.rec + } + + self.rec = self.state.GetOrNewStateObject(self.tx.Recipient) + return self.rec +} + +func (self *StateTransition) UseGas(amount *big.Int) error { + if self.gas.Cmp(amount) < 0 { + return OutOfGasError() + } + self.gas.Sub(self.gas, amount) + + return nil +} + +func (self *StateTransition) AddGas(amount *big.Int) { + self.gas.Add(self.gas, amount) +} + +func (self *StateTransition) BuyGas() error { + var err error + + sender := self.Sender() + if sender.Balance().Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance()) + } + + coinbase := self.Coinbase() + err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + if err != nil { + return err + } + + self.AddGas(self.tx.Gas) + sender.SubAmount(self.tx.GasValue()) + + return nil +} + +func (self *StateTransition) RefundGas() { + coinbase, sender := self.Coinbase(), self.Sender() + coinbase.RefundGas(self.gas, self.tx.GasPrice) + + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice) + sender.AddAmount(remaining) +} + +func (self *StateTransition) preCheck() (err error) { + var ( + tx = self.tx + sender = self.Sender() + ) + + // Make sure this transaction's nonce is correct + if sender.Nonce != tx.Nonce { + return NonceError(tx.Nonce, sender.Nonce) + } + + // Pre-pay gas / Buy gas of the coinbase account + if err = self.BuyGas(); err != nil { + return err + } + + return nil +} + +func (self *StateTransition) TransitionState() (err error) { + statelogger.Debugf("(~) %x\n", self.tx.Hash()) + + // XXX Transactions after this point are considered valid. + if err = self.preCheck(); err != nil { + return + } + + var ( + tx = self.tx + sender = self.Sender() + receiver *ethstate.StateObject + ) + + defer self.RefundGas() + + // Increment the nonce for the next transaction + sender.Nonce += 1 + + // Transaction gas + if err = self.UseGas(vm.GasTx); err != nil { + return + } + + // Pay data gas + dataPrice := big.NewInt(int64(len(self.data))) + dataPrice.Mul(dataPrice, vm.GasData) + if err = self.UseGas(dataPrice); err != nil { + return + } + + if sender.Balance().Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) + } + + var snapshot *ethstate.State + // If the receiver is nil it's a contract (\0*32). + if tx.CreatesContract() { + // Subtract the (irreversible) amount from the senders account + sender.SubAmount(self.value) + + snapshot = self.state.Copy() + + // Create a new state object for the contract + receiver = MakeContract(tx, self.state) + self.rec = receiver + if receiver == nil { + return fmt.Errorf("Unable to create contract") + } + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) + } else { + receiver = self.Receiver() + + // Subtract the amount from the senders account + sender.SubAmount(self.value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) + + snapshot = self.state.Copy() + } + + msg := self.state.Manifest().AddMessage(ðstate.Message{ + To: receiver.Address(), From: sender.Address(), + Input: self.tx.Data, + Origin: sender.Address(), + Block: self.block.Hash(), Timestamp: self.block.Time, Coinbase: self.block.Coinbase, Number: self.block.Number, + Value: self.value, + }) + + // Process the init code and create 'valid' contract + if IsContractAddr(self.receiver) { + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + self.data = nil + + code, evmerr := self.Eval(msg, receiver.Init(), receiver) + if evmerr != nil { + self.state.Set(snapshot) + + statelogger.Debugf("Error during init execution %v", evmerr) + } + + receiver.Code = code + msg.Output = code + } else { + if len(receiver.Code) > 0 { + ret, evmerr := self.Eval(msg, receiver.Code, receiver) + if evmerr != nil { + self.state.Set(snapshot) + + statelogger.Debugf("Error during code execution %v", evmerr) + } + + msg.Output = ret + } else { + // Add default LOG. Default = big(sender.addr) + 1 + addr := ethutil.BigD(receiver.Address()) + self.state.AddLog(ethstate.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) + } + } + + return +} + +func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject) (ret []byte, err error) { + var ( + transactor = self.Sender() + state = self.state + env = NewEnv(state, self.tx, self.block) + callerClosure = vm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) + ) + + evm := vm.New(env, vm.DebugVmTy) + ret, _, err = callerClosure.Call(evm, self.tx.Data) + + return +} + +// Converts an transaction in to a state object +func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject { + addr := tx.CreationAddress(state) + + contract := state.GetOrNewStateObject(addr) + contract.InitCode = tx.Data + + return contract +} diff --git a/chain/transaction.go b/chain/transaction.go new file mode 100644 index 000000000..ef95432af --- /dev/null +++ b/chain/transaction.go @@ -0,0 +1,271 @@ +package chain + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/obscuren/secp256k1-go" +) + +var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +func IsContractAddr(addr []byte) bool { + return len(addr) == 0 + //return bytes.Compare(addr, ContractAddr) == 0 +} + +type Transaction struct { + Nonce uint64 + Recipient []byte + Value *big.Int + Gas *big.Int + GasPrice *big.Int + Data []byte + v byte + r, s []byte + + // Indicates whether this tx is a contract creation transaction + contractCreation bool +} + +func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { + return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} +} + +func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)} +} + +func NewTransactionFromBytes(data []byte) *Transaction { + tx := &Transaction{} + tx.RlpDecode(data) + + return tx +} + +func NewTransactionFromValue(val *ethutil.Value) *Transaction { + tx := &Transaction{} + tx.RlpValueDecode(val) + + return tx +} + +func (self *Transaction) GasValue() *big.Int { + return new(big.Int).Mul(self.Gas, self.GasPrice) +} + +func (self *Transaction) TotalValue() *big.Int { + v := self.GasValue() + return v.Add(v, self.Value) +} + +func (tx *Transaction) Hash() []byte { + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + + return ethcrypto.Sha3(ethutil.NewValue(data).Encode()) +} + +func (tx *Transaction) CreatesContract() bool { + return tx.contractCreation +} + +/* Deprecated */ +func (tx *Transaction) IsContract() bool { + return tx.CreatesContract() +} + +func (tx *Transaction) CreationAddress(state *ethstate.State) []byte { + // Generate a new address + addr := ethcrypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] + //for i := uint64(0); state.GetStateObject(addr) != nil; i++ { + // addr = ethcrypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] + //} + + return addr +} + +func (tx *Transaction) Signature(key []byte) []byte { + hash := tx.Hash() + + sig, _ := secp256k1.Sign(hash, key) + + return sig +} + +func (tx *Transaction) PublicKey() []byte { + hash := tx.Hash() + + // TODO + r := ethutil.LeftPadBytes(tx.r, 32) + s := ethutil.LeftPadBytes(tx.s, 32) + + sig := append(r, s...) + sig = append(sig, tx.v-27) + + pubkey := ethcrypto.Ecrecover(append(hash, sig...)) + //pubkey, _ := secp256k1.RecoverPubkey(hash, sig) + + return pubkey +} + +func (tx *Transaction) Sender() []byte { + pubkey := tx.PublicKey() + + // Validate the returned key. + // Return nil if public key isn't in full format + if pubkey[0] != 4 { + return nil + } + + return ethcrypto.Sha3(pubkey[1:])[12:] +} + +func (tx *Transaction) Sign(privk []byte) error { + + sig := tx.Signature(privk) + + tx.r = sig[:32] + tx.s = sig[32:64] + tx.v = sig[64] + 27 + + return nil +} + +func (tx *Transaction) RlpData() interface{} { + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + + // TODO Remove prefixing zero's + + return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes()) +} + +func (tx *Transaction) RlpValue() *ethutil.Value { + return ethutil.NewValue(tx.RlpData()) +} + +func (tx *Transaction) RlpEncode() []byte { + return tx.RlpValue().Encode() +} + +func (tx *Transaction) RlpDecode(data []byte) { + tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) +} + +func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { + tx.Nonce = decoder.Get(0).Uint() + tx.GasPrice = decoder.Get(1).BigInt() + tx.Gas = decoder.Get(2).BigInt() + tx.Recipient = decoder.Get(3).Bytes() + tx.Value = decoder.Get(4).BigInt() + tx.Data = decoder.Get(5).Bytes() + tx.v = byte(decoder.Get(6).Uint()) + + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() + + if IsContractAddr(tx.Recipient) { + tx.contractCreation = true + } +} + +func (tx *Transaction) String() string { + return fmt.Sprintf(` + TX(%x) + Contract: %v + From: %x + To: %x + Nonce: %v + GasPrice: %v + Gas: %v + Value: %v + Data: 0x%x + V: 0x%x + R: 0x%x + S: 0x%x + `, + tx.Hash(), + len(tx.Recipient) == 0, + tx.Sender(), + tx.Recipient, + tx.Nonce, + tx.GasPrice, + tx.Gas, + tx.Value, + tx.Data, + tx.v, + tx.r, + tx.s) +} + +type Receipt struct { + PostState []byte + CumulativeGasUsed *big.Int + Bloom []byte + logs ethstate.Logs +} + +func NewRecieptFromValue(val *ethutil.Value) *Receipt { + r := &Receipt{} + r.RlpValueDecode(val) + + return r +} + +func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { + self.PostState = decoder.Get(0).Bytes() + self.CumulativeGasUsed = decoder.Get(1).BigInt() + self.Bloom = decoder.Get(2).Bytes() + + it := decoder.Get(3).NewIterator() + for it.Next() { + self.logs = append(self.logs, ethstate.NewLogFromValue(it.Value())) + } +} + +func (self *Receipt) RlpData() interface{} { + return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} +} + +func (self *Receipt) RlpEncode() []byte { + return ethutil.Encode(self.RlpData()) +} + +func (self *Receipt) Cmp(other *Receipt) bool { + if bytes.Compare(self.PostState, other.PostState) != 0 { + return false + } + + return true +} + +type Receipts []*Receipt + +func (self Receipts) Len() int { return len(self) } +func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) } + +// Transaction slice type for basic sorting +type Transactions []*Transaction + +func (self Transactions) RlpData() interface{} { + // Marshal the transactions of this block + enc := make([]interface{}, len(self)) + for i, tx := range self { + // Cast it to a string (safe) + enc[i] = tx.RlpData() + } + + return enc +} +func (s Transactions) Len() int { return len(s) } +func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) } + +type TxByNonce struct{ Transactions } + +func (s TxByNonce) Less(i, j int) bool { + return s.Transactions[i].Nonce < s.Transactions[j].Nonce +} diff --git a/chain/transaction_pool.go b/chain/transaction_pool.go new file mode 100644 index 000000000..861ebdf00 --- /dev/null +++ b/chain/transaction_pool.go @@ -0,0 +1,245 @@ +package chain + +import ( + "bytes" + "container/list" + "fmt" + "math/big" + "sync" + + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethwire" +) + +var txplogger = ethlog.NewLogger("TXP") + +const txPoolQueueSize = 50 + +type TxPoolHook chan *Transaction +type TxMsgTy byte + +const ( + minGasPrice = 1000000 +) + +var MinGasPrice = big.NewInt(10000000000000) + +type TxMsg struct { + Tx *Transaction + Type TxMsgTy +} + +func EachTx(pool *list.List, it func(*Transaction, *list.Element) bool) { + for e := pool.Front(); e != nil; e = e.Next() { + if it(e.Value.(*Transaction), e) { + break + } + } +} + +func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { + for e := pool.Front(); e != nil; e = e.Next() { + if tx, ok := e.Value.(*Transaction); ok { + if finder(tx, e) { + return tx + } + } + } + + return nil +} + +type TxProcessor interface { + ProcessTransaction(tx *Transaction) +} + +// The tx pool a thread safe transaction pool handler. In order to +// guarantee a non blocking pool we use a queue channel which can be +// independently read without needing access to the actual pool. If the +// pool is being drained or synced for whatever reason the transactions +// will simple queue up and handled when the mutex is freed. +type TxPool struct { + Ethereum EthManager + // The mutex for accessing the Tx pool. + mutex sync.Mutex + // Queueing channel for reading and writing incoming + // transactions to + queueChan chan *Transaction + // Quiting channel + quit chan bool + // The actual pool + pool *list.List + + SecondaryProcessor TxProcessor + + subscribers []chan TxMsg +} + +func NewTxPool(ethereum EthManager) *TxPool { + return &TxPool{ + pool: list.New(), + queueChan: make(chan *Transaction, txPoolQueueSize), + quit: make(chan bool), + Ethereum: ethereum, + } +} + +// Blocking function. Don't use directly. Use QueueTransaction instead +func (pool *TxPool) addTransaction(tx *Transaction) { + pool.mutex.Lock() + defer pool.mutex.Unlock() + + pool.pool.PushBack(tx) + + // Broadcast the transaction to the rest of the peers + pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) +} + +func (pool *TxPool) ValidateTransaction(tx *Transaction) error { + // Get the last block so we can retrieve the sender and receiver from + // the merkle trie + block := pool.Ethereum.ChainManager().CurrentBlock + // Something has gone horribly wrong if this happens + if block == nil { + return fmt.Errorf("[TXPL] No last block on the block chain") + } + + if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 { + return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) + } + + if tx.GasPrice.Cmp(MinGasPrice) < 0 { + return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice) + } + + // Get the sender + //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) + sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) + + totAmount := new(big.Int).Set(tx.Value) + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + if sender.Balance().Cmp(totAmount) < 0 { + return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + } + + if tx.IsContract() { + if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { + return fmt.Errorf("[TXPL] Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) + } + } + + // Increment the nonce making each tx valid only once to prevent replay + // attacks + + return nil +} + +func (pool *TxPool) queueHandler() { +out: + for { + select { + case tx := <-pool.queueChan: + hash := tx.Hash() + foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { + return bytes.Compare(tx.Hash(), hash) == 0 + }) + + if foundTx != nil { + break + } + + // Validate the transaction + err := pool.ValidateTransaction(tx) + if err != nil { + txplogger.Debugln("Validating Tx failed", err) + } else { + // Call blocking version. + pool.addTransaction(tx) + + tmp := make([]byte, 4) + copy(tmp, tx.Recipient) + + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) + + // Notify the subscribers + pool.Ethereum.EventMux().Post(TxPreEvent{tx}) + } + case <-pool.quit: + break out + } + } +} + +func (pool *TxPool) QueueTransaction(tx *Transaction) { + pool.queueChan <- tx +} + +func (pool *TxPool) CurrentTransactions() []*Transaction { + pool.mutex.Lock() + defer pool.mutex.Unlock() + + txList := make([]*Transaction, pool.pool.Len()) + i := 0 + for e := pool.pool.Front(); e != nil; e = e.Next() { + tx := e.Value.(*Transaction) + + txList[i] = tx + + i++ + } + + return txList +} + +func (pool *TxPool) RemoveInvalid(state *ethstate.State) { + pool.mutex.Lock() + defer pool.mutex.Unlock() + + for e := pool.pool.Front(); e != nil; e = e.Next() { + tx := e.Value.(*Transaction) + sender := state.GetAccount(tx.Sender()) + err := pool.ValidateTransaction(tx) + if err != nil || sender.Nonce >= tx.Nonce { + pool.pool.Remove(e) + } + } +} + +func (self *TxPool) RemoveSet(txs Transactions) { + self.mutex.Lock() + defer self.mutex.Unlock() + + for _, tx := range txs { + EachTx(self.pool, func(t *Transaction, element *list.Element) bool { + if t == tx { + self.pool.Remove(element) + return true // To stop the loop + } + return false + }) + } +} + +func (pool *TxPool) Flush() []*Transaction { + txList := pool.CurrentTransactions() + + // Recreate a new list all together + // XXX Is this the fastest way? + pool.pool = list.New() + + return txList +} + +func (pool *TxPool) Start() { + go pool.queueHandler() +} + +func (pool *TxPool) Stop() { + close(pool.quit) + + pool.Flush() + + txplogger.Infoln("Stopped") +} diff --git a/chain/transaction_test.go b/chain/transaction_test.go new file mode 100644 index 000000000..fef1d2010 --- /dev/null +++ b/chain/transaction_test.go @@ -0,0 +1 @@ +package chain diff --git a/chain/types.go b/chain/types.go new file mode 100644 index 000000000..9871ae07b --- /dev/null +++ b/chain/types.go @@ -0,0 +1,312 @@ +package chain + +import ( + "fmt" +) + +type OpCode int + +// Op codes +const ( + // 0x0 range - arithmetic ops + STOP = 0x00 + ADD = 0x01 + MUL = 0x02 + SUB = 0x03 + DIV = 0x04 + SDIV = 0x05 + MOD = 0x06 + SMOD = 0x07 + EXP = 0x08 + BNOT = 0x09 + LT = 0x0a + GT = 0x0b + SLT = 0x0c + SGT = 0x0d + EQ = 0x0e + NOT = 0x0f + + // 0x10 range - bit ops + AND = 0x10 + OR = 0x11 + XOR = 0x12 + BYTE = 0x13 + ADDMOD = 0x14 + MULMOD = 0x15 + + // 0x20 range - crypto + SHA3 = 0x20 + + // 0x30 range - closure state + ADDRESS = 0x30 + BALANCE = 0x31 + ORIGIN = 0x32 + CALLER = 0x33 + CALLVALUE = 0x34 + CALLDATALOAD = 0x35 + CALLDATASIZE = 0x36 + CALLDATACOPY = 0x37 + CODESIZE = 0x38 + CODECOPY = 0x39 + GASPRICE = 0x3a + EXTCODESIZE = 0x3b + EXTCODECOPY = 0x3c + + // 0x40 range - block operations + PREVHASH = 0x40 + COINBASE = 0x41 + TIMESTAMP = 0x42 + NUMBER = 0x43 + DIFFICULTY = 0x44 + GASLIMIT = 0x45 + + // 0x50 range - 'storage' and execution + POP = 0x50 + //DUP = 0x51 + //SWAP = 0x52 + MLOAD = 0x53 + MSTORE = 0x54 + MSTORE8 = 0x55 + SLOAD = 0x56 + SSTORE = 0x57 + JUMP = 0x58 + JUMPI = 0x59 + PC = 0x5a + MSIZE = 0x5b + GAS = 0x5c + + // 0x60 range + PUSH1 = 0x60 + PUSH2 = 0x61 + PUSH3 = 0x62 + PUSH4 = 0x63 + PUSH5 = 0x64 + PUSH6 = 0x65 + PUSH7 = 0x66 + PUSH8 = 0x67 + PUSH9 = 0x68 + PUSH10 = 0x69 + PUSH11 = 0x6a + PUSH12 = 0x6b + PUSH13 = 0x6c + PUSH14 = 0x6d + PUSH15 = 0x6e + PUSH16 = 0x6f + PUSH17 = 0x70 + PUSH18 = 0x71 + PUSH19 = 0x72 + PUSH20 = 0x73 + PUSH21 = 0x74 + PUSH22 = 0x75 + PUSH23 = 0x76 + PUSH24 = 0x77 + PUSH25 = 0x78 + PUSH26 = 0x79 + PUSH27 = 0x7a + PUSH28 = 0x7b + PUSH29 = 0x7c + PUSH30 = 0x7d + PUSH31 = 0x7e + PUSH32 = 0x7f + + DUP1 = 0x80 + DUP2 = 0x81 + DUP3 = 0x82 + DUP4 = 0x83 + DUP5 = 0x84 + DUP6 = 0x85 + DUP7 = 0x86 + DUP8 = 0x87 + DUP9 = 0x88 + DUP10 = 0x89 + DUP11 = 0x8a + DUP12 = 0x8b + DUP13 = 0x8c + DUP14 = 0x8d + DUP15 = 0x8e + DUP16 = 0x8f + + SWAP1 = 0x90 + SWAP2 = 0x91 + SWAP3 = 0x92 + SWAP4 = 0x93 + SWAP5 = 0x94 + SWAP6 = 0x95 + SWAP7 = 0x96 + SWAP8 = 0x97 + SWAP9 = 0x98 + SWAP10 = 0x99 + SWAP11 = 0x9a + SWAP12 = 0x9b + SWAP13 = 0x9c + SWAP14 = 0x9d + SWAP15 = 0x9e + SWAP16 = 0x9f + + // 0xf0 range - closures + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 + CALLCODE = 0xf3 + + // 0x70 range - other + LOG = 0xfe // XXX Unofficial + SUICIDE = 0xff +) + +// Since the opcodes aren't all in order we can't use a regular slice +var opCodeToString = map[OpCode]string{ + // 0x0 range - arithmetic ops + STOP: "STOP", + ADD: "ADD", + MUL: "MUL", + SUB: "SUB", + DIV: "DIV", + SDIV: "SDIV", + MOD: "MOD", + SMOD: "SMOD", + EXP: "EXP", + BNOT: "BNOT", + LT: "LT", + GT: "GT", + SLT: "SLT", + SGT: "SGT", + EQ: "EQ", + NOT: "NOT", + + // 0x10 range - bit ops + AND: "AND", + OR: "OR", + XOR: "XOR", + BYTE: "BYTE", + ADDMOD: "ADDMOD", + MULMOD: "MULMOD", + + // 0x20 range - crypto + SHA3: "SHA3", + + // 0x30 range - closure state + ADDRESS: "ADDRESS", + BALANCE: "BALANCE", + ORIGIN: "ORIGIN", + CALLER: "CALLER", + CALLVALUE: "CALLVALUE", + CALLDATALOAD: "CALLDATALOAD", + CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", + GASPRICE: "TXGASPRICE", + + // 0x40 range - block operations + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", + + // 0x50 range - 'storage' and execution + POP: "POP", + //DUP: "DUP", + //SWAP: "SWAP", + MLOAD: "MLOAD", + MSTORE: "MSTORE", + MSTORE8: "MSTORE8", + SLOAD: "SLOAD", + SSTORE: "SSTORE", + JUMP: "JUMP", + JUMPI: "JUMPI", + PC: "PC", + MSIZE: "MSIZE", + GAS: "GAS", + + // 0x60 range - push + PUSH1: "PUSH1", + PUSH2: "PUSH2", + PUSH3: "PUSH3", + PUSH4: "PUSH4", + PUSH5: "PUSH5", + PUSH6: "PUSH6", + PUSH7: "PUSH7", + PUSH8: "PUSH8", + PUSH9: "PUSH9", + PUSH10: "PUSH10", + PUSH11: "PUSH11", + PUSH12: "PUSH12", + PUSH13: "PUSH13", + PUSH14: "PUSH14", + PUSH15: "PUSH15", + PUSH16: "PUSH16", + PUSH17: "PUSH17", + PUSH18: "PUSH18", + PUSH19: "PUSH19", + PUSH20: "PUSH20", + PUSH21: "PUSH21", + PUSH22: "PUSH22", + PUSH23: "PUSH23", + PUSH24: "PUSH24", + PUSH25: "PUSH25", + PUSH26: "PUSH26", + PUSH27: "PUSH27", + PUSH28: "PUSH28", + PUSH29: "PUSH29", + PUSH30: "PUSH30", + PUSH31: "PUSH31", + PUSH32: "PUSH32", + + DUP1: "DUP1", + DUP2: "DUP2", + DUP3: "DUP3", + DUP4: "DUP4", + DUP5: "DUP5", + DUP6: "DUP6", + DUP7: "DUP7", + DUP8: "DUP8", + DUP9: "DUP9", + DUP10: "DUP10", + DUP11: "DUP11", + DUP12: "DUP12", + DUP13: "DUP13", + DUP14: "DUP14", + DUP15: "DUP15", + DUP16: "DUP16", + + SWAP1: "SWAP1", + SWAP2: "SWAP2", + SWAP3: "SWAP3", + SWAP4: "SWAP4", + SWAP5: "SWAP5", + SWAP6: "SWAP6", + SWAP7: "SWAP7", + SWAP8: "SWAP8", + SWAP9: "SWAP9", + SWAP10: "SWAP10", + SWAP11: "SWAP11", + SWAP12: "SWAP12", + SWAP13: "SWAP13", + SWAP14: "SWAP14", + SWAP15: "SWAP15", + SWAP16: "SWAP16", + + // 0xf0 range + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", + CALLCODE: "CALLCODE", + + // 0x70 range - other + LOG: "LOG", + SUICIDE: "SUICIDE", +} + +func (o OpCode) String() string { + str := opCodeToString[o] + if len(str) == 0 { + return fmt.Sprintf("Missing opcode 0x%x", int(o)) + } + + return str +} diff --git a/chain/vm_env.go b/chain/vm_env.go new file mode 100644 index 000000000..d42351713 --- /dev/null +++ b/chain/vm_env.go @@ -0,0 +1,39 @@ +package chain + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/vm" +) + +type VMEnv struct { + state *ethstate.State + block *Block + tx *Transaction +} + +func NewEnv(state *ethstate.State, tx *Transaction, block *Block) *VMEnv { + return &VMEnv{ + state: state, + block: block, + tx: tx, + } +} + +func (self *VMEnv) Origin() []byte { return self.tx.Sender() } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number } +func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } +func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } +func (self *VMEnv) Time() int64 { return self.block.Time } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } +func (self *VMEnv) Value() *big.Int { return self.tx.Value } +func (self *VMEnv) State() *ethstate.State { return self.state } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) AddLog(log ethstate.Log) { + self.state.AddLog(log) +} +func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { + return vm.Transfer(from, to, amount) +} diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go index 0a6427938..03d35a574 100644 --- a/cmd/mist/bindings.go +++ b/cmd/mist/bindings.go @@ -22,7 +22,7 @@ import ( "os" "strconv" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethpipe" "github.com/ethereum/go-ethereum/ethutil" @@ -110,7 +110,7 @@ func (self *Gui) DumpState(hash, path string) { if len(hash) == 0 { stateDump = self.eth.StateManager().CurrentState().Dump() } else { - var block *ethchain.Block + var block *chain.Block if hash[0] == '#' { i, _ := strconv.Atoi(hash[1:]) block = self.eth.ChainManager().GetBlockByNumber(uint64(i)) diff --git a/cmd/mist/debugger.go b/cmd/mist/debugger.go index ff3a30b3b..d786a0395 100644 --- a/cmd/mist/debugger.go +++ b/cmd/mist/debugger.go @@ -24,7 +24,7 @@ import ( "strings" "unicode" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/utils" @@ -81,7 +81,7 @@ func (self *DebuggerWindow) SetData(data string) { func (self *DebuggerWindow) SetAsm(data []byte) { self.win.Root().Call("clearAsm") - dis := ethchain.Disassemble(data) + dis := chain.Disassemble(data) for _, str := range dis { self.win.Root().Call("setAsm", str) } diff --git a/cmd/mist/ext_app.go b/cmd/mist/ext_app.go index 7680106f0..cb014aec4 100644 --- a/cmd/mist/ext_app.go +++ b/cmd/mist/ext_app.go @@ -20,7 +20,7 @@ package main import ( "encoding/json" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethpipe" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/event" @@ -36,7 +36,7 @@ type AppContainer interface { Window() *qml.Window Engine() *qml.Engine - NewBlock(*ethchain.Block) + NewBlock(*chain.Block) NewWatcher(chan bool) Messages(ethstate.Messages, string) Post(string, int) @@ -44,12 +44,12 @@ type AppContainer interface { type ExtApplication struct { *ethpipe.JSPipe - eth ethchain.EthManager + eth chain.EthManager events event.Subscription watcherQuitChan chan bool - filters map[string]*ethchain.Filter + filters map[string]*chain.Filter container AppContainer lib *UiLib @@ -60,7 +60,7 @@ func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication { JSPipe: ethpipe.NewJSPipe(lib.eth), eth: lib.eth, watcherQuitChan: make(chan bool), - filters: make(map[string]*ethchain.Filter), + filters: make(map[string]*chain.Filter), container: container, lib: lib, } @@ -80,7 +80,7 @@ func (app *ExtApplication) run() { // Subscribe to events mux := app.lib.eth.EventMux() - app.events = mux.Subscribe(ethchain.NewBlockEvent{}, ethstate.Messages(nil)) + app.events = mux.Subscribe(chain.NewBlockEvent{}, ethstate.Messages(nil)) // Call the main loop go app.mainLoop() @@ -106,7 +106,7 @@ func (app *ExtApplication) stop() { func (app *ExtApplication) mainLoop() { for ev := range app.events.Chan() { switch ev := ev.(type) { - case ethchain.NewBlockEvent: + case chain.NewBlockEvent: app.container.NewBlock(ev.Block) case ethstate.Messages: diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index e6da33475..c917ad06e 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -31,7 +31,7 @@ import ( "time" "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethminer" @@ -286,7 +286,7 @@ func (gui *Gui) loadAddressBook() { } } -func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) { +func (gui *Gui) insertTransaction(window string, tx *chain.Transaction) { pipe := ethpipe.New(gui.eth) nameReg := pipe.World().Config().Get("NameReg") addr := gui.address() @@ -336,7 +336,7 @@ func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) { func (gui *Gui) readPreviousTransactions() { it := gui.txDb.Db().NewIterator(nil, nil) for it.Next() { - tx := ethchain.NewTransactionFromBytes(it.Value()) + tx := chain.NewTransactionFromBytes(it.Value()) gui.insertTransaction("post", tx) @@ -344,7 +344,7 @@ func (gui *Gui) readPreviousTransactions() { it.Release() } -func (gui *Gui) processBlock(block *ethchain.Block, initial bool) { +func (gui *Gui) processBlock(block *chain.Block, initial bool) { name := strings.Trim(gui.pipe.World().Config().Get("NameReg").Storage(block.Coinbase).Str(), "\x00") b := ethpipe.NewJSBlock(block) b.Name = name @@ -407,9 +407,9 @@ func (gui *Gui) update() { events := gui.eth.EventMux().Subscribe( eth.ChainSyncEvent{}, eth.PeerListEvent{}, - ethchain.NewBlockEvent{}, - ethchain.TxPreEvent{}, - ethchain.TxPostEvent{}, + chain.NewBlockEvent{}, + chain.TxPreEvent{}, + chain.TxPostEvent{}, ethminer.Event{}, ) @@ -425,13 +425,13 @@ func (gui *Gui) update() { return } switch ev := ev.(type) { - case ethchain.NewBlockEvent: + case chain.NewBlockEvent: gui.processBlock(ev.Block, false) if bytes.Compare(ev.Block.Coinbase, gui.address()) == 0 { gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Balance(), nil) } - case ethchain.TxPreEvent: + case chain.TxPreEvent: tx := ev.Tx object := state.GetAccount(gui.address()) @@ -444,7 +444,7 @@ func (gui *Gui) update() { gui.setWalletValue(object.Balance(), unconfirmedFunds) gui.insertTransaction("pre", tx) - case ethchain.TxPostEvent: + case chain.TxPostEvent: tx := ev.Tx object := state.GetAccount(gui.address()) diff --git a/cmd/mist/html_container.go b/cmd/mist/html_container.go index 2e2818027..96bae1a9a 100644 --- a/cmd/mist/html_container.go +++ b/cmd/mist/html_container.go @@ -27,7 +27,7 @@ import ( "path" "path/filepath" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethpipe" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" @@ -138,7 +138,7 @@ func (app *HtmlApplication) Window() *qml.Window { return app.win } -func (app *HtmlApplication) NewBlock(block *ethchain.Block) { +func (app *HtmlApplication) NewBlock(block *chain.Block) { b := ðpipe.JSBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())} app.webView.Call("onNewBlockCb", b) } diff --git a/cmd/mist/qml_container.go b/cmd/mist/qml_container.go index 7538fb919..3318786e7 100644 --- a/cmd/mist/qml_container.go +++ b/cmd/mist/qml_container.go @@ -21,7 +21,7 @@ import ( "fmt" "runtime" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethpipe" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" @@ -65,7 +65,7 @@ func (app *QmlApplication) NewWatcher(quitChan chan bool) { } // Events -func (app *QmlApplication) NewBlock(block *ethchain.Block) { +func (app *QmlApplication) NewBlock(block *chain.Block) { pblock := ðpipe.JSBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())} app.win.Call("onNewBlockCb", pblock) } diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go index 32ca3c2c9..a9b560b6f 100644 --- a/cmd/mist/ui_lib.go +++ b/cmd/mist/ui_lib.go @@ -25,7 +25,7 @@ import ( "strings" "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethcrypto" "github.com/ethereum/go-ethereum/ethpipe" "github.com/ethereum/go-ethereum/ethstate" @@ -120,7 +120,7 @@ func (self *UiLib) PastPeers() *ethutil.List { } func (self *UiLib) ImportTx(rlpTx string) { - tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx)) + tx := chain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx)) self.eth.TxPool().QueueTransaction(tx) } @@ -221,8 +221,8 @@ func (self *UiLib) NewFilter(object map[string]interface{}) (id int) { } func (self *UiLib) NewFilterString(typ string) (id int) { - filter := ethchain.NewFilter(self.eth) - filter.BlockCallback = func(block *ethchain.Block) { + filter := chain.NewFilter(self.eth) + filter.BlockCallback = func(block *chain.Block) { self.win.Root().Call("invokeFilterCallback", "{}", id) } id = self.eth.InstallFilter(filter) diff --git a/ethchain/.gitignore b/ethchain/.gitignore deleted file mode 100644 index f725d58d1..000000000 --- a/ethchain/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. -# -# If you find yourself ignoring temporary files generated by your text editor -# or operating system, you probably want to add a global ignore instead: -# git config --global core.excludesfile ~/.gitignore_global - -/tmp -*/**/*un~ -*un~ -.DS_Store -*/**/.DS_Store - diff --git a/ethchain/asm.go b/ethchain/asm.go deleted file mode 100644 index 57bb2fcf9..000000000 --- a/ethchain/asm.go +++ /dev/null @@ -1,45 +0,0 @@ -package ethchain - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/ethutil" -) - -func Disassemble(script []byte) (asm []string) { - pc := new(big.Int) - for { - if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { - return - } - - // Get the memory location of pc - val := script[pc.Int64()] - // Get the opcode (it must be an opcode!) - op := OpCode(val) - - asm = append(asm, fmt.Sprintf("%04v: %v", pc, op)) - - switch op { - case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: - pc.Add(pc, ethutil.Big1) - a := int64(op) - int64(PUSH1) + 1 - if int(pc.Int64()+a) > len(script) { - return - } - - data := script[pc.Int64() : pc.Int64()+a] - if len(data) == 0 { - data = []byte{0} - } - asm = append(asm, fmt.Sprintf("%04v: 0x%x", pc, data)) - - pc.Add(pc, big.NewInt(a-1)) - } - - pc.Add(pc, ethutil.Big1) - } - - return asm -} diff --git a/ethchain/block.go b/ethchain/block.go deleted file mode 100644 index a10da97ec..000000000 --- a/ethchain/block.go +++ /dev/null @@ -1,419 +0,0 @@ -package ethchain - -import ( - "bytes" - "fmt" - "math/big" - "sort" - "time" - - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethtrie" - "github.com/ethereum/go-ethereum/ethutil" -) - -type BlockInfo struct { - Number uint64 - Hash []byte - Parent []byte - TD *big.Int -} - -func (bi *BlockInfo) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - bi.Number = decoder.Get(0).Uint() - bi.Hash = decoder.Get(1).Bytes() - bi.Parent = decoder.Get(2).Bytes() - bi.TD = decoder.Get(3).BigInt() -} - -func (bi *BlockInfo) RlpEncode() []byte { - return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD}) -} - -type Blocks []*Block - -func (self Blocks) AsSet() ethutil.UniqueSet { - set := make(ethutil.UniqueSet) - for _, block := range self { - set.Insert(block.Hash()) - } - - return set -} - -type BlockBy func(b1, b2 *Block) bool - -func (self BlockBy) Sort(blocks Blocks) { - bs := blockSorter{ - blocks: blocks, - by: self, - } - sort.Sort(bs) -} - -type blockSorter struct { - blocks Blocks - by func(b1, b2 *Block) bool -} - -func (self blockSorter) Len() int { return len(self.blocks) } -func (self blockSorter) Swap(i, j int) { - self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] -} -func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } - -func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } - -type Block struct { - // Hash to the previous block - PrevHash ethutil.Bytes - // Uncles of this block - Uncles Blocks - UncleSha []byte - // The coin base address - Coinbase []byte - // Block Trie state - //state *ethutil.Trie - state *ethstate.State - // Difficulty for the current block - Difficulty *big.Int - // Creation time - Time int64 - // The block number - Number *big.Int - // Minimum Gas Price - MinGasPrice *big.Int - // Gas limit - GasLimit *big.Int - // Gas used - GasUsed *big.Int - // Extra data - Extra string - // Block Nonce for verification - Nonce ethutil.Bytes - // List of transactions and/or contracts - transactions Transactions - receipts Receipts - TxSha, ReceiptSha []byte - LogsBloom []byte -} - -func NewBlockFromBytes(raw []byte) *Block { - block := &Block{} - block.RlpDecode(raw) - - return block -} - -// New block takes a raw encoded string -func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block { - block := &Block{} - block.RlpValueDecode(rlpValue) - - return block -} - -func CreateBlock(root interface{}, - prevHash []byte, - base []byte, - Difficulty *big.Int, - Nonce []byte, - extra string) *Block { - - block := &Block{ - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), - Extra: extra, - UncleSha: nil, - GasUsed: new(big.Int), - MinGasPrice: new(big.Int), - GasLimit: new(big.Int), - } - block.SetUncles([]*Block{}) - - block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, root)) - - return block -} - -// Returns a hash of the block -func (block *Block) Hash() ethutil.Bytes { - return ethcrypto.Sha3(ethutil.NewValue(block.header()).Encode()) - //return ethcrypto.Sha3(block.Value().Encode()) -} - -func (block *Block) HashNoNonce() []byte { - return ethcrypto.Sha3(ethutil.Encode(block.miningHeader())) -} - -func (block *Block) State() *ethstate.State { - return block.state -} - -func (block *Block) Transactions() []*Transaction { - return block.transactions -} - -func (block *Block) CalcGasLimit(parent *Block) *big.Int { - if block.Number.Cmp(big.NewInt(0)) == 0 { - return ethutil.BigPow(10, 6) - } - - // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 - - previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit) - current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed), big.NewRat(6, 5)) - curInt := new(big.Int).Div(current.Num(), current.Denom()) - - result := new(big.Int).Add(previous, curInt) - result.Div(result, big.NewInt(1024)) - - min := big.NewInt(125000) - - return ethutil.BigMax(min, result) -} - -func (block *Block) BlockInfo() BlockInfo { - bi := BlockInfo{} - data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) - bi.RlpDecode(data) - - return bi -} - -func (self *Block) GetTransaction(hash []byte) *Transaction { - for _, tx := range self.transactions { - if bytes.Compare(tx.Hash(), hash) == 0 { - return tx - } - } - - return nil -} - -// Sync the block's state and contract respectively -func (block *Block) Sync() { - block.state.Sync() -} - -func (block *Block) Undo() { - // Sync the block state itself - block.state.Reset() -} - -/////// Block Encoding -func (block *Block) rlpReceipts() interface{} { - // Marshal the transactions of this block - encR := make([]interface{}, len(block.receipts)) - for i, r := range block.receipts { - // Cast it to a string (safe) - encR[i] = r.RlpData() - } - - return encR -} - -func (block *Block) rlpUncles() interface{} { - // Marshal the transactions of this block - uncles := make([]interface{}, len(block.Uncles)) - for i, uncle := range block.Uncles { - // Cast it to a string (safe) - uncles[i] = uncle.header() - } - - return uncles -} - -func (block *Block) SetUncles(uncles []*Block) { - block.Uncles = uncles - block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) -} - -func (self *Block) SetReceipts(receipts Receipts) { - self.receipts = receipts - self.ReceiptSha = DeriveSha(receipts) - self.LogsBloom = CreateBloom(self) -} - -func (self *Block) SetTransactions(txs Transactions) { - self.transactions = txs - self.TxSha = DeriveSha(txs) -} - -func (block *Block) Value() *ethutil.Value { - return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()}) -} - -func (block *Block) RlpEncode() []byte { - // Encode a slice interface which contains the header and the list of - // transactions. - return block.Value().Encode() -} - -func (block *Block) RlpDecode(data []byte) { - rlpValue := ethutil.NewValueFromBytes(data) - block.RlpValueDecode(rlpValue) -} - -func (block *Block) RlpValueDecode(decoder *ethutil.Value) { - block.setHeader(decoder.Get(0)) - - // Tx list might be empty if this is an uncle. Uncles only have their - // header set. - if decoder.Get(1).IsNil() == false { // Yes explicitness - //receipts := decoder.Get(1) - //block.receipts = make([]*Receipt, receipts.Len()) - txs := decoder.Get(1) - block.transactions = make(Transactions, txs.Len()) - for i := 0; i < txs.Len(); i++ { - block.transactions[i] = NewTransactionFromValue(txs.Get(i)) - //receipt := NewRecieptFromValue(receipts.Get(i)) - //block.transactions[i] = receipt.Tx - //block.receipts[i] = receipt - } - - } - - if decoder.Get(2).IsNil() == false { // Yes explicitness - uncles := decoder.Get(2) - block.Uncles = make([]*Block, uncles.Len()) - for i := 0; i < uncles.Len(); i++ { - block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i)) - } - } - -} - -func (self *Block) setHeader(header *ethutil.Value) { - self.PrevHash = header.Get(0).Bytes() - self.UncleSha = header.Get(1).Bytes() - self.Coinbase = header.Get(2).Bytes() - self.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) - self.TxSha = header.Get(4).Bytes() - self.ReceiptSha = header.Get(5).Bytes() - self.LogsBloom = header.Get(6).Bytes() - self.Difficulty = header.Get(7).BigInt() - self.Number = header.Get(8).BigInt() - self.MinGasPrice = header.Get(9).BigInt() - self.GasLimit = header.Get(10).BigInt() - self.GasUsed = header.Get(11).BigInt() - self.Time = int64(header.Get(12).BigInt().Uint64()) - self.Extra = header.Get(13).Str() - self.Nonce = header.Get(14).Bytes() -} - -func NewUncleBlockFromValue(header *ethutil.Value) *Block { - block := &Block{} - block.setHeader(header) - - return block -} - -func (block *Block) Trie() *ethtrie.Trie { - return block.state.Trie -} - -func (block *Block) GetRoot() interface{} { - return block.state.Trie.Root -} - -func (block *Block) Diff() *big.Int { - return block.Difficulty -} - -func (self *Block) Receipts() []*Receipt { - return self.receipts -} - -func (block *Block) miningHeader() []interface{} { - return []interface{}{ - // Sha of the previous block - block.PrevHash, - // Sha of uncles - block.UncleSha, - // Coinbase address - block.Coinbase, - // root state - block.state.Trie.Root, - // tx root - block.TxSha, - // Sha of tx - block.ReceiptSha, - // Bloom - block.LogsBloom, - // Current block Difficulty - block.Difficulty, - // The block number - block.Number, - // Block minimum gas price - block.MinGasPrice, - // Block upper gas bound - block.GasLimit, - // Block gas used - block.GasUsed, - // Time the block was found? - block.Time, - // Extra data - block.Extra, - } -} - -func (block *Block) header() []interface{} { - return append(block.miningHeader(), block.Nonce) -} - -func (block *Block) String() string { - return fmt.Sprintf(` - BLOCK(%x): Size: %v - PrevHash: %x - UncleSha: %x - Coinbase: %x - Root: %x - TxSha %x - ReceiptSha: %x - Bloom: %x - Difficulty: %v - Number: %v - MinGas: %v - MaxLimit: %v - GasUsed: %v - Time: %v - Extra: %v - Nonce: %x - NumTx: %v -`, - block.Hash(), - block.Size(), - block.PrevHash, - block.UncleSha, - block.Coinbase, - block.state.Trie.Root, - block.TxSha, - block.ReceiptSha, - block.LogsBloom, - block.Difficulty, - block.Number, - block.MinGasPrice, - block.GasLimit, - block.GasUsed, - block.Time, - block.Extra, - block.Nonce, - len(block.transactions), - ) -} - -func (self *Block) Size() ethutil.StorageSize { - return ethutil.StorageSize(len(self.RlpEncode())) -} - -// Implement RlpEncodable -func (self *Block) RlpData() interface{} { - return self.Value().Val -} diff --git a/ethchain/bloom.go b/ethchain/bloom.go deleted file mode 100644 index 5317ca0b1..000000000 --- a/ethchain/bloom.go +++ /dev/null @@ -1,47 +0,0 @@ -package ethchain - -type BloomFilter struct { - bin []byte -} - -func NewBloomFilter(bin []byte) *BloomFilter { - if bin == nil { - bin = make([]byte, 256) - } - - return &BloomFilter{ - bin: bin, - } -} - -func (self *BloomFilter) Set(addr []byte) { - if len(addr) < 8 { - chainlogger.Warnf("err: bloom set to small: %x\n", addr) - - return - } - - for _, i := range addr[len(addr)-8:] { - self.bin[i] = 1 - } -} - -func (self *BloomFilter) Search(addr []byte) bool { - if len(addr) < 8 { - chainlogger.Warnf("err: bloom search to small: %x\n", addr) - - return false - } - - for _, i := range addr[len(addr)-8:] { - if self.bin[i] == 0 { - return false - } - } - - return true -} - -func (self *BloomFilter) Bin() []byte { - return self.bin -} diff --git a/ethchain/bloom9.go b/ethchain/bloom9.go deleted file mode 100644 index 8fa7b6339..000000000 --- a/ethchain/bloom9.go +++ /dev/null @@ -1,55 +0,0 @@ -package ethchain - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethutil" -) - -func CreateBloom(block *Block) []byte { - bin := new(big.Int) - bin.Or(bin, bloom9(block.Coinbase)) - for _, receipt := range block.Receipts() { - bin.Or(bin, LogsBloom(receipt.logs)) - } - - return bin.Bytes() -} - -func LogsBloom(logs ethstate.Logs) *big.Int { - bin := new(big.Int) - for _, log := range logs { - data := [][]byte{log.Address} - for _, topic := range log.Topics { - data = append(data, topic) - } - - if log.Data != nil { - data = append(data, log.Data) - } - - for _, b := range data { - bin.Or(bin, bloom9(b)) - } - } - - return bin -} - -func bloom9(b []byte) *big.Int { - r := new(big.Int) - for _, i := range []int{0, 2, 4} { - t := big.NewInt(1) - r.Or(r, t.Lsh(t, uint(b[i+1])+256*(uint(b[i])&1))) - } - - return r -} - -func BloomLookup(bin, topic []byte) bool { - bloom := ethutil.BigD(bin) - cmp := bloom9(topic) - - return bloom.And(bloom, cmp).Cmp(cmp) == 0 -} diff --git a/ethchain/bloom9_test.go b/ethchain/bloom9_test.go deleted file mode 100644 index 40f30f35d..000000000 --- a/ethchain/bloom9_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package ethchain - -import ( - "testing" - - "github.com/ethereum/go-ethereum/vm" -) - -func TestBloom9(t *testing.T) { - testCase := []byte("testtest") - bin := LogsBloom([]vm.Log{vm.Log{testCase, [][]byte{[]byte("hellohello")}, nil}}).Bytes() - res := BloomLookup(bin, testCase) - - if !res { - t.Errorf("Bloom lookup failed") - } -} diff --git a/ethchain/bloom_test.go b/ethchain/bloom_test.go deleted file mode 100644 index ea53d539c..000000000 --- a/ethchain/bloom_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package ethchain - -import "testing" - -func TestBloomFilter(t *testing.T) { - bf := NewBloomFilter(nil) - - a := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} - bf.Set(a) - - b := []byte{10, 11, 12, 13, 14, 15, 16, 17, 18, 19} - - if bf.Search(a) == false { - t.Error("Expected 'a' to yield true using a bloom filter") - } - - if bf.Search(b) { - t.Error("Expected 'b' not to field trie using a bloom filter") - } -} diff --git a/ethchain/chain_manager.go b/ethchain/chain_manager.go deleted file mode 100644 index 46990bb22..000000000 --- a/ethchain/chain_manager.go +++ /dev/null @@ -1,289 +0,0 @@ -package ethchain - -import ( - "bytes" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/ethlog" - "github.com/ethereum/go-ethereum/ethutil" -) - -var chainlogger = ethlog.NewLogger("CHAIN") - -type ChainManager struct { - Ethereum EthManager - // The famous, the fabulous Mister GENESIIIIIIS (block) - genesisBlock *Block - // Last known total difficulty - TD *big.Int - - LastBlockNumber uint64 - - CurrentBlock *Block - LastBlockHash []byte -} - -func NewChainManager(ethereum EthManager) *ChainManager { - bc := &ChainManager{} - bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) - bc.Ethereum = ethereum - - bc.setLastBlock() - - return bc -} - -func (bc *ChainManager) Genesis() *Block { - return bc.genesisBlock -} - -func (bc *ChainManager) NewBlock(coinbase []byte) *Block { - var root interface{} - hash := ZeroHash256 - - if bc.CurrentBlock != nil { - root = bc.CurrentBlock.state.Trie.Root - hash = bc.LastBlockHash - } - - block := CreateBlock( - root, - hash, - coinbase, - ethutil.BigPow(2, 32), - nil, - "") - - block.MinGasPrice = big.NewInt(10000000000000) - - parent := bc.CurrentBlock - if parent != nil { - block.Difficulty = CalcDifficulty(block, parent) - block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) - - } - - return block -} - -func CalcDifficulty(block, parent *Block) *big.Int { - diff := new(big.Int) - - adjust := new(big.Int).Rsh(parent.Difficulty, 10) - if block.Time >= parent.Time+5 { - diff.Sub(parent.Difficulty, adjust) - } else { - diff.Add(parent.Difficulty, adjust) - } - - return diff -} - -func (bc *ChainManager) Reset() { - AddTestNetFunds(bc.genesisBlock) - - bc.genesisBlock.state.Trie.Sync() - // Prepare the genesis block - bc.Add(bc.genesisBlock) - bc.CurrentBlock = bc.genesisBlock - - bc.SetTotalDifficulty(ethutil.Big("0")) - - // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) -} - -func (bc *ChainManager) HasBlock(hash []byte) bool { - data, _ := ethutil.Config.Db.Get(hash) - return len(data) != 0 -} - -// TODO: At one point we might want to save a block by prevHash in the db to optimise this... -func (bc *ChainManager) HasBlockWithPrevHash(hash []byte) bool { - block := bc.CurrentBlock - - for ; block != nil; block = bc.GetBlock(block.PrevHash) { - if bytes.Compare(hash, block.PrevHash) == 0 { - return true - } - } - return false -} - -func (bc *ChainManager) CalculateBlockTD(block *Block) *big.Int { - blockDiff := new(big.Int) - - for _, uncle := range block.Uncles { - blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty) - } - blockDiff = blockDiff.Add(blockDiff, block.Difficulty) - - return blockDiff -} - -func (bc *ChainManager) GenesisBlock() *Block { - return bc.genesisBlock -} - -func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { - block := self.GetBlock(hash) - if block == nil { - return - } - - // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list) - for i := uint64(0); i < max; i++ { - chain = append(chain, block.Hash()) - - if block.Number.Cmp(ethutil.Big0) <= 0 { - break - } - - block = self.GetBlock(block.PrevHash) - } - - return -} - -func AddTestNetFunds(block *Block) { - for _, addr := range []string{ - "51ba59315b3a95761d0863b05ccc7a7f54703d99", - "e4157b34ea9615cfbde6b4fda419828124b70c78", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - } { - codedAddr := ethutil.Hex2Bytes(addr) - account := block.state.GetAccount(codedAddr) - account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) - block.state.UpdateStateObject(account) - } -} - -func (bc *ChainManager) setLastBlock() { - data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) - if len(data) != 0 { - // Prep genesis - AddTestNetFunds(bc.genesisBlock) - - block := NewBlockFromBytes(data) - bc.CurrentBlock = block - bc.LastBlockHash = block.Hash() - bc.LastBlockNumber = block.Number.Uint64() - - // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - } else { - bc.Reset() - } - - chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) -} - -func (bc *ChainManager) SetTotalDifficulty(td *big.Int) { - ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) - bc.TD = td -} - -// Add a block to the chain and record addition information -func (bc *ChainManager) Add(block *Block) { - bc.writeBlockInfo(block) - // Prepare the genesis block - - bc.CurrentBlock = block - bc.LastBlockHash = block.Hash() - - encodedBlock := block.RlpEncode() - ethutil.Config.Db.Put(block.Hash(), encodedBlock) - ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) -} - -func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) { - parent := self.GetBlock(block.PrevHash) - if parent == nil { - return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) - } - - parentTd := parent.BlockInfo().TD - - uncleDiff := new(big.Int) - for _, uncle := range block.Uncles { - uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) - } - - td := new(big.Int) - td = td.Add(parentTd, uncleDiff) - td = td.Add(td, block.Difficulty) - - return td, nil -} - -func (bc *ChainManager) GetBlock(hash []byte) *Block { - data, _ := ethutil.Config.Db.Get(hash) - if len(data) == 0 { - return nil - } - - return NewBlockFromBytes(data) -} - -func (self *ChainManager) GetBlockByNumber(num uint64) *Block { - block := self.CurrentBlock - for ; block != nil; block = self.GetBlock(block.PrevHash) { - if block.Number.Uint64() == num { - break - } - } - - if block != nil && block.Number.Uint64() == 0 && num != 0 { - return nil - } - - return block -} - -func (self *ChainManager) GetBlockBack(num uint64) *Block { - block := self.CurrentBlock - - for ; num != 0 && block != nil; num-- { - block = self.GetBlock(block.PrevHash) - } - - return block -} - -func (bc *ChainManager) BlockInfoByHash(hash []byte) BlockInfo { - bi := BlockInfo{} - data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) - bi.RlpDecode(data) - - return bi -} - -func (bc *ChainManager) BlockInfo(block *Block) BlockInfo { - bi := BlockInfo{} - data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) - bi.RlpDecode(data) - - return bi -} - -// Unexported method for writing extra non-essential block info to the db -func (bc *ChainManager) writeBlockInfo(block *Block) { - bc.LastBlockNumber++ - bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD} - - // For now we use the block hash with the words "info" appended as key - ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode()) -} - -func (bc *ChainManager) Stop() { - if bc.CurrentBlock != nil { - chainlogger.Infoln("Stopped") - } -} diff --git a/ethchain/chain_manager_test.go b/ethchain/chain_manager_test.go deleted file mode 100644 index 3603fd8a7..000000000 --- a/ethchain/chain_manager_test.go +++ /dev/null @@ -1 +0,0 @@ -package ethchain diff --git a/ethchain/dagger.go b/ethchain/dagger.go deleted file mode 100644 index 7efcf469d..000000000 --- a/ethchain/dagger.go +++ /dev/null @@ -1,239 +0,0 @@ -package ethchain - -import ( - "hash" - "math/big" - "math/rand" - "time" - - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethlog" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/obscuren/sha3" -) - -var powlogger = ethlog.NewLogger("POW") - -type PoW interface { - Search(block *Block, stop <-chan struct{}) []byte - Verify(hash []byte, diff *big.Int, nonce []byte) bool - GetHashrate() int64 - Turbo(bool) -} - -type EasyPow struct { - hash *big.Int - HashRate int64 - turbo bool -} - -func (pow *EasyPow) GetHashrate() int64 { - return pow.HashRate -} - -func (pow *EasyPow) Turbo(on bool) { - pow.turbo = on -} - -func (pow *EasyPow) Search(block *Block, stop <-chan struct{}) []byte { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - hash := block.HashNoNonce() - diff := block.Difficulty - i := int64(0) - start := time.Now().UnixNano() - t := time.Now() - - for { - select { - case <-stop: - powlogger.Infoln("Breaking from mining") - return nil - default: - i++ - - if time.Since(t) > (1 * time.Second) { - elapsed := time.Now().UnixNano() - start - hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - pow.HashRate = int64(hashes) - powlogger.Infoln("Hashing @", int64(pow.HashRate), "khash") - - t = time.Now() - } - - sha := ethcrypto.Sha3(big.NewInt(r.Int63()).Bytes()) - if pow.Verify(hash, diff, sha) { - return sha - } - } - - if !pow.turbo { - time.Sleep(20 * time.Microsecond) - } - } - - return nil -} - -func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool { - sha := sha3.NewKeccak256() - - d := append(hash, nonce...) - sha.Write(d) - - v := ethutil.BigPow(2, 256) - ret := new(big.Int).Div(v, diff) - - res := new(big.Int) - res.SetBytes(sha.Sum(nil)) - - return res.Cmp(ret) == -1 -} - -func (pow *EasyPow) SetHash(hash *big.Int) { -} - -type Dagger struct { - 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())) - - for i := 0; i < 1000; i++ { - rnd := r.Int63() - - res := dag.Eval(big.NewInt(rnd)) - powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj) - if res.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 - } - } - - 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 - - dag.hash = hash - - obj := ethutil.BigPow(2, 256) - obj = obj.Div(obj, diff) - - Found = false - resChan := make(chan int64, 3) - var res int64 - - 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 - } - } - - return big.NewInt(res) -} - -func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool { - dag.hash = hash - - obj := ethutil.BigPow(2, 256) - obj = obj.Div(obj, diff) - - return dag.Eval(nonce).Cmp(obj) < 0 -} - -func DaggerVerify(hash, diff, nonce *big.Int) bool { - dagger := &Dagger{} - dagger.hash = hash - - obj := ethutil.BigPow(2, 256) - obj = obj.Div(obj, diff) - - 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 -} - -func Sum(sha hash.Hash) []byte { - //in := make([]byte, 32) - return sha.Sum(nil) -} - -func (dag *Dagger) Eval(N *big.Int) *big.Int { - pow := ethutil.BigPow(2, 26) - dag.xn = pow.Div(N, pow) - - sha := sha3.NewKeccak256() - sha.Reset() - ret := 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()) - - b.SetBytes(Sum(d)) - pk := (b.Uint64() & 0x1ffffff) - - sha.Write(dag.Node(9, pk).Bytes()) - } - - return ret.SetBytes(Sum(sha)) -} diff --git a/ethchain/dagger_test.go b/ethchain/dagger_test.go deleted file mode 100644 index 2ffba0485..000000000 --- a/ethchain/dagger_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package ethchain - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/ethutil" -) - -func BenchmarkDaggerSearch(b *testing.B) { - hash := big.NewInt(0) - diff := ethutil.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) -} diff --git a/ethchain/derive_sha.go b/ethchain/derive_sha.go deleted file mode 100644 index b41252e39..000000000 --- a/ethchain/derive_sha.go +++ /dev/null @@ -1,20 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/go-ethereum/ethtrie" - "github.com/ethereum/go-ethereum/ethutil" -) - -type DerivableList interface { - Len() int - GetRlp(i int) []byte -} - -func DeriveSha(list DerivableList) []byte { - trie := ethtrie.New(ethutil.Config.Db, "") - for i := 0; i < list.Len(); i++ { - trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i))) - } - - return trie.GetRoot() -} diff --git a/ethchain/error.go b/ethchain/error.go deleted file mode 100644 index 82949141a..000000000 --- a/ethchain/error.go +++ /dev/null @@ -1,116 +0,0 @@ -package ethchain - -import ( - "fmt" - "math/big" -) - -// Parent error. In case a parent is unknown this error will be thrown -// by the block manager -type ParentErr struct { - Message string -} - -func (err *ParentErr) Error() string { - return err.Message -} - -func ParentError(hash []byte) error { - return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)} -} - -func IsParentErr(err error) bool { - _, ok := err.(*ParentErr) - - return ok -} - -type UncleErr struct { - Message string -} - -func (err *UncleErr) Error() string { - return err.Message -} - -func UncleError(str string) error { - return &UncleErr{Message: str} -} - -func IsUncleErr(err error) bool { - _, ok := err.(*UncleErr) - - return ok -} - -// Block validation error. If any validation fails, this error will be thrown -type ValidationErr struct { - Message string -} - -func (err *ValidationErr) Error() string { - return err.Message -} - -func ValidationError(format string, v ...interface{}) *ValidationErr { - return &ValidationErr{Message: fmt.Sprintf(format, v...)} -} - -func IsValidationErr(err error) bool { - _, ok := err.(*ValidationErr) - - return ok -} - -type GasLimitErr struct { - Message string - Is, Max *big.Int -} - -func IsGasLimitErr(err error) bool { - _, ok := err.(*GasLimitErr) - - return ok -} -func (err *GasLimitErr) Error() string { - return err.Message -} -func GasLimitError(is, max *big.Int) *GasLimitErr { - return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max} -} - -type NonceErr struct { - Message string - Is, Exp uint64 -} - -func (err *NonceErr) Error() string { - return err.Message -} - -func NonceError(is, exp uint64) *NonceErr { - return &NonceErr{Message: fmt.Sprintf("Nonce err. Is %d, expected %d", is, exp), Is: is, Exp: exp} -} - -func IsNonceErr(err error) bool { - _, ok := err.(*NonceErr) - - return ok -} - -type OutOfGasErr struct { - Message string -} - -func OutOfGasError() *OutOfGasErr { - return &OutOfGasErr{Message: "Out of gas"} -} -func (self *OutOfGasErr) Error() string { - return self.Message -} - -func IsOutOfGasErr(err error) bool { - _, ok := err.(*OutOfGasErr) - - return ok -} diff --git a/ethchain/events.go b/ethchain/events.go deleted file mode 100644 index 304e741b7..000000000 --- a/ethchain/events.go +++ /dev/null @@ -1,10 +0,0 @@ -package ethchain - -// TxPreEvent is posted when a transaction enters the transaction pool. -type TxPreEvent struct{ Tx *Transaction } - -// TxPostEvent is posted when a transaction has been processed. -type TxPostEvent struct{ Tx *Transaction } - -// NewBlockEvent is posted when a block has been imported. -type NewBlockEvent struct{ Block *Block } diff --git a/ethchain/fees.go b/ethchain/fees.go deleted file mode 100644 index 901357439..000000000 --- a/ethchain/fees.go +++ /dev/null @@ -1,7 +0,0 @@ -package ethchain - -import ( - "math/big" -) - -var BlockReward *big.Int = big.NewInt(1.5e+18) diff --git a/ethchain/filter.go b/ethchain/filter.go deleted file mode 100644 index a88d36467..000000000 --- a/ethchain/filter.go +++ /dev/null @@ -1,197 +0,0 @@ -package ethchain - -import ( - "bytes" - "math" - - "github.com/ethereum/go-ethereum/ethstate" -) - -type AccountChange struct { - Address, StateAddress []byte -} - -// Filtering interface -type Filter struct { - eth EthManager - earliest int64 - latest int64 - skip int - from, to [][]byte - max int - - Altered []AccountChange - - BlockCallback func(*Block) - MessageCallback func(ethstate.Messages) -} - -// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block -// is interesting or not. -func NewFilter(eth EthManager) *Filter { - return &Filter{eth: eth} -} - -func (self *Filter) AddAltered(address, stateAddress []byte) { - self.Altered = append(self.Altered, AccountChange{address, stateAddress}) -} - -// Set the earliest and latest block for filtering. -// -1 = latest block (i.e., the current block) -// hash = particular hash from-to -func (self *Filter) SetEarliestBlock(earliest int64) { - self.earliest = earliest -} - -func (self *Filter) SetLatestBlock(latest int64) { - self.latest = latest -} - -func (self *Filter) SetFrom(addr [][]byte) { - self.from = addr -} - -func (self *Filter) AddFrom(addr []byte) { - self.from = append(self.from, addr) -} - -func (self *Filter) SetTo(addr [][]byte) { - self.to = addr -} - -func (self *Filter) AddTo(addr []byte) { - self.to = append(self.to, addr) -} - -func (self *Filter) SetMax(max int) { - self.max = max -} - -func (self *Filter) SetSkip(skip int) { - self.skip = skip -} - -// Run filters messages with the current parameters set -func (self *Filter) Find() []*ethstate.Message { - var earliestBlockNo uint64 = uint64(self.earliest) - if self.earliest == -1 { - earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() - } - var latestBlockNo uint64 = uint64(self.latest) - if self.latest == -1 { - latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() - } - - var ( - messages []*ethstate.Message - block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo) - quit bool - ) - for i := 0; !quit && block != nil; i++ { - // Quit on latest - switch { - case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0: - quit = true - case self.max <= len(messages): - break - } - - // Use bloom filtering to see if this block is interesting given the - // current parameters - if self.bloomFilter(block) { - // Get the messages of the block - msgs, err := self.eth.StateManager().GetMessages(block) - if err != nil { - chainlogger.Warnln("err: filter get messages ", err) - - break - } - - messages = append(messages, self.FilterMessages(msgs)...) - } - - block = self.eth.ChainManager().GetBlock(block.PrevHash) - } - - skip := int(math.Min(float64(len(messages)), float64(self.skip))) - - return messages[skip:] -} - -func includes(addresses [][]byte, a []byte) (found bool) { - for _, addr := range addresses { - if bytes.Compare(addr, a) == 0 { - return true - } - } - - return -} - -func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message { - var messages []*ethstate.Message - - // Filter the messages for interesting stuff - for _, message := range msgs { - if len(self.to) > 0 && !includes(self.to, message.To) { - continue - } - - if len(self.from) > 0 && !includes(self.from, message.From) { - continue - } - - var match bool - if len(self.Altered) == 0 { - match = true - } - - for _, accountChange := range self.Altered { - if len(accountChange.Address) > 0 && bytes.Compare(message.To, accountChange.Address) != 0 { - continue - } - - if len(accountChange.StateAddress) > 0 && !includes(message.ChangedAddresses, accountChange.StateAddress) { - continue - } - - match = true - break - } - - if !match { - continue - } - - messages = append(messages, message) - } - - return messages -} - -func (self *Filter) bloomFilter(block *Block) bool { - var fromIncluded, toIncluded bool - if len(self.from) > 0 { - for _, from := range self.from { - if BloomLookup(block.LogsBloom, from) { - fromIncluded = true - break - } - } - } else { - fromIncluded = true - } - - if len(self.to) > 0 { - for _, to := range self.to { - if BloomLookup(block.LogsBloom, to) { - toIncluded = true - break - } - } - } else { - toIncluded = true - } - - return fromIncluded && toIncluded -} diff --git a/ethchain/filter_test.go b/ethchain/filter_test.go deleted file mode 100644 index e569b3774..000000000 --- a/ethchain/filter_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package ethchain - -import "testing" - -func TestFilter(t *testing.T) { - NewFilter(NewTestManager()) -} diff --git a/ethchain/genesis.go b/ethchain/genesis.go deleted file mode 100644 index d94e658b6..000000000 --- a/ethchain/genesis.go +++ /dev/null @@ -1,53 +0,0 @@ -package ethchain - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethutil" -) - -/* - * This is the special genesis block. - */ - -var ZeroHash256 = make([]byte, 32) -var ZeroHash160 = make([]byte, 20) -var ZeroHash512 = make([]byte, 64) -var EmptyShaList = ethcrypto.Sha3(ethutil.Encode([]interface{}{})) - -var GenesisHeader = []interface{}{ - // Previous hash (none) - ZeroHash256, - // Empty uncles - EmptyShaList, - // Coinbase - ZeroHash160, - // Root state - EmptyShaList, - // tx sha - EmptyShaList, - // receipt list - EmptyShaList, - // bloom - ZeroHash512, - // Difficulty - //ethutil.BigPow(2, 22), - big.NewInt(131072), - // Number - ethutil.Big0, - // Block minimum gas price - ethutil.Big0, - // Block upper gas bound - big.NewInt(1000000), - // Block gas used - ethutil.Big0, - // Time - ethutil.Big0, - // Extra - nil, - // Nonce - ethcrypto.Sha3(big.NewInt(42).Bytes()), -} - -var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} diff --git a/ethchain/helper_test.go b/ethchain/helper_test.go deleted file mode 100644 index a863c7541..000000000 --- a/ethchain/helper_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package ethchain - -import ( - "container/list" - "fmt" - - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/ethwire" - "github.com/ethereum/go-ethereum/event" -) - -// Implement our EthTest Manager -type TestManager struct { - stateManager *StateManager - eventMux *event.TypeMux - - db ethutil.Database - txPool *TxPool - blockChain *ChainManager - Blocks []*Block -} - -func (s *TestManager) IsListening() bool { - return false -} - -func (s *TestManager) IsMining() bool { - return false -} - -func (s *TestManager) PeerCount() int { - return 0 -} - -func (s *TestManager) Peers() *list.List { - return list.New() -} - -func (s *TestManager) ChainManager() *ChainManager { - return s.blockChain -} - -func (tm *TestManager) TxPool() *TxPool { - return tm.txPool -} - -func (tm *TestManager) StateManager() *StateManager { - return tm.stateManager -} - -func (tm *TestManager) EventMux() *event.TypeMux { - return tm.eventMux -} -func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { - fmt.Println("Broadcast not implemented") -} - -func (tm *TestManager) ClientIdentity() ethwire.ClientIdentity { - return nil -} -func (tm *TestManager) KeyManager() *ethcrypto.KeyManager { - return nil -} - -func (tm *TestManager) Db() ethutil.Database { - return tm.db -} - -func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH") - - db, err := ethdb.NewMemDatabase() - if err != nil { - fmt.Println("Could not create mem-db, failing") - return nil - } - ethutil.Config.Db = db - - testManager := &TestManager{} - testManager.eventMux = new(event.TypeMux) - testManager.db = db - testManager.txPool = NewTxPool(testManager) - testManager.blockChain = NewChainManager(testManager) - testManager.stateManager = NewStateManager(testManager) - - // Start the tx pool - testManager.txPool.Start() - - return testManager -} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go deleted file mode 100644 index d48d96a51..000000000 --- a/ethchain/state_manager.go +++ /dev/null @@ -1,451 +0,0 @@ -package ethchain - -import ( - "bytes" - "container/list" - "fmt" - "math/big" - "os" - "sync" - "time" - - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethlog" - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/ethwire" - "github.com/ethereum/go-ethereum/event" -) - -var statelogger = ethlog.NewLogger("BLOCK") - -type Peer interface { - Inbound() bool - LastSend() time.Time - LastPong() int64 - Host() []byte - Port() uint16 - Version() string - PingTime() string - Connected() *int32 - Caps() *ethutil.Value -} - -type EthManager interface { - StateManager() *StateManager - ChainManager() *ChainManager - TxPool() *TxPool - Broadcast(msgType ethwire.MsgType, data []interface{}) - PeerCount() int - IsMining() bool - IsListening() bool - Peers() *list.List - KeyManager() *ethcrypto.KeyManager - ClientIdentity() ethwire.ClientIdentity - Db() ethutil.Database - EventMux() *event.TypeMux -} - -type StateManager struct { - // Mutex for locking the block processor. Blocks can only be handled one at a time - mutex sync.Mutex - // Canonical block chain - bc *ChainManager - // non-persistent key/value memory storage - mem map[string]*big.Int - // Proof of work used for validating - Pow PoW - // The ethereum manager interface - eth EthManager - // The managed states - // Transiently state. The trans state isn't ever saved, validated and - // it could be used for setting account nonces without effecting - // the main states. - transState *ethstate.State - // Mining state. The mining state is used purely and solely by the mining - // operation. - miningState *ethstate.State - - // The last attempted block is mainly used for debugging purposes - // This does not have to be a valid block and will be set during - // 'Process' & canonical validation. - lastAttemptedBlock *Block - - events event.Subscription -} - -func NewStateManager(ethereum EthManager) *StateManager { - sm := &StateManager{ - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - eth: ethereum, - bc: ethereum.ChainManager(), - } - sm.transState = ethereum.ChainManager().CurrentBlock.State().Copy() - sm.miningState = ethereum.ChainManager().CurrentBlock.State().Copy() - - return sm -} - -func (self *StateManager) Start() { - statelogger.Debugln("Starting state manager") - self.events = self.eth.EventMux().Subscribe(Blocks(nil)) - go self.updateThread() -} - -func (self *StateManager) Stop() { - statelogger.Debugln("Stopping state manager") - self.events.Unsubscribe() -} - -func (self *StateManager) updateThread() { - for ev := range self.events.Chan() { - for _, block := range ev.(Blocks) { - err := self.Process(block) - if err != nil { - statelogger.Infoln(err) - statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) - statelogger.Debugln(block) - break - } - } - } -} - -func (sm *StateManager) CurrentState() *ethstate.State { - return sm.eth.ChainManager().CurrentBlock.State() -} - -func (sm *StateManager) TransState() *ethstate.State { - return sm.transState -} - -func (sm *StateManager) MiningState() *ethstate.State { - return sm.miningState -} - -func (sm *StateManager) NewMiningState() *ethstate.State { - sm.miningState = sm.eth.ChainManager().CurrentBlock.State().Copy() - - return sm.miningState -} - -func (sm *StateManager) ChainManager() *ChainManager { - return sm.bc -} - -func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, state *ethstate.State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, Transactions, error) { - var ( - receipts Receipts - handled, unhandled Transactions - erroneous Transactions - totalUsedGas = big.NewInt(0) - err error - ) - -done: - for i, tx := range txs { - // If we are mining this block and validating we want to set the logs back to 0 - state.EmptyLogs() - - txGas := new(big.Int).Set(tx.Gas) - - cb := state.GetStateObject(coinbase.Address()) - st := NewStateTransition(cb, tx, state, block) - err = st.TransitionState() - if err != nil { - statelogger.Infoln(err) - switch { - case IsNonceErr(err): - err = nil // ignore error - continue - case IsGasLimitErr(err): - unhandled = txs[i:] - - break done - default: - statelogger.Infoln(err) - erroneous = append(erroneous, tx) - err = nil - continue - //return nil, nil, nil, err - } - } - - // Update the state with pending changes - state.Update() - - txGas.Sub(txGas, st.gas) - cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) - //receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} - receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(state.Logs()).Bytes(), state.Logs()} - - if i < len(block.Receipts()) { - original := block.Receipts()[i] - if !original.Cmp(receipt) { - if ethutil.Config.Diff { - os.Exit(1) - } - - err := fmt.Errorf("#%d receipt failed (r) %v ~ %x <=> (c) %v ~ %x (%x...)", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], tx.Hash()[0:4]) - - return nil, nil, nil, nil, err - } - } - - // Notify all subscribers - go self.eth.EventMux().Post(TxPostEvent{tx}) - - receipts = append(receipts, receipt) - handled = append(handled, tx) - - if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { - state.CreateOutputForDiff() - } - } - - parent.GasUsed = totalUsedGas - - return receipts, handled, unhandled, erroneous, err -} - -func (sm *StateManager) Process(block *Block) (err error) { - // Processing a blocks may never happen simultaneously - sm.mutex.Lock() - defer sm.mutex.Unlock() - - if sm.bc.HasBlock(block.Hash()) { - return nil - } - - if !sm.bc.HasBlock(block.PrevHash) { - return ParentError(block.PrevHash) - } - - sm.lastAttemptedBlock = block - - var ( - parent = sm.bc.GetBlock(block.PrevHash) - state = parent.State() - ) - - // Defer the Undo on the Trie. If the block processing happened - // we don't want to undo but since undo only happens on dirty - // nodes this won't happen because Commit would have been called - // before that. - defer state.Reset() - - if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { - fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) - } - - txSha := DeriveSha(block.transactions) - if bytes.Compare(txSha, block.TxSha) != 0 { - return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.TxSha, txSha) - } - - receipts, err := sm.ApplyDiff(state, parent, block) - if err != nil { - return err - } - - receiptSha := DeriveSha(receipts) - if bytes.Compare(receiptSha, block.ReceiptSha) != 0 { - return fmt.Errorf("Error validating receipt sha. Received %x, got %x", block.ReceiptSha, receiptSha) - } - - // Block validation - if err = sm.ValidateBlock(block); err != nil { - statelogger.Errorln("Error validating block:", err) - return err - } - - if err = sm.AccumelateRewards(state, block, parent); err != nil { - statelogger.Errorln("Error accumulating reward", err) - return err - } - - state.Update() - - if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) - return - } - - // Calculate the new total difficulty and sync back to the db - if sm.CalculateTD(block) { - // Sync the current block's state to the database and cancelling out the deferred Undo - state.Sync() - - // Add the block to the chain - sm.bc.Add(block) - - // TODO at this point we should also insert LOGS in to a database - - sm.transState = state.Copy() - - statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) - - state.Manifest().Reset() - - sm.eth.TxPool().RemoveSet(block.Transactions()) - } else { - statelogger.Errorln("total diff failed") - } - - return nil -} - -func (sm *StateManager) ApplyDiff(state *ethstate.State, parent, block *Block) (receipts Receipts, err error) { - coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.SetGasPool(block.CalcGasLimit(parent)) - - // Process the transactions on to current block - receipts, _, _, _, err = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) - if err != nil { - return nil, err - } - - return receipts, nil -} - -func (sm *StateManager) CalculateTD(block *Block) bool { - uncleDiff := new(big.Int) - for _, uncle := range block.Uncles { - uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) - } - - // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty - td := new(big.Int) - td = td.Add(sm.bc.TD, uncleDiff) - td = td.Add(td, block.Difficulty) - - // The new TD will only be accepted if the new difficulty is - // is greater than the previous. - if td.Cmp(sm.bc.TD) > 0 { - // Set the new total difficulty back to the block chain - sm.bc.SetTotalDifficulty(td) - - return true - } - - return false -} - -// Validates the current block. Returns an error if the block was invalid, -// an uncle or anything that isn't on the current block chain. -// Validation validates easy over difficult (dagger takes longer time = difficult) -func (sm *StateManager) ValidateBlock(block *Block) error { - // Check each uncle's previous hash. In order for it to be valid - // is if it has the same block hash as the current - parent := sm.bc.GetBlock(block.PrevHash) - /* - for _, uncle := range block.Uncles { - if bytes.Compare(uncle.PrevHash,parent.PrevHash) != 0 { - return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x",parent.PrevHash, uncle.PrevHash) - } - } - */ - - expd := CalcDifficulty(block, parent) - if expd.Cmp(block.Difficulty) < 0 { - return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) - } - - diff := block.Time - parent.Time - if diff < 0 { - return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time) - } - - /* XXX - // New blocks must be within the 15 minute range of the last block. - if diff > int64(15*time.Minute) { - return ValidationError("Block is too far in the future of last block (> 15 minutes)") - } - */ - - // Verify the nonce of the block. Return an error if it's not valid - if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { - return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce)) - } - - return nil -} - -func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error { - reward := new(big.Int).Set(BlockReward) - - knownUncles := ethutil.Set(parent.Uncles) - nonces := ethutil.NewSet(block.Nonce) - for _, uncle := range block.Uncles { - if nonces.Include(uncle.Nonce) { - // Error not unique - return UncleError("Uncle not unique") - } - - uncleParent := sm.bc.GetBlock(uncle.PrevHash) - if uncleParent == nil { - return UncleError("Uncle's parent unknown") - } - - if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 { - return UncleError("Uncle too old") - } - - if knownUncles.Include(uncle.Hash()) { - return UncleError("Uncle in chain") - } - - nonces.Insert(uncle.Nonce) - - r := new(big.Int) - r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) - - uncleAccount := state.GetAccount(uncle.Coinbase) - uncleAccount.AddAmount(r) - - reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) - } - - // Get the account associated with the coinbase - account := state.GetAccount(block.Coinbase) - // Reward amount of ether to the coinbase address - account.AddAmount(reward) - - return nil -} - -// Manifest will handle both creating notifications and generating bloom bin data -func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { - bloomf := NewBloomFilter(nil) - - for _, msg := range state.Manifest().Messages { - bloomf.Set(msg.To) - bloomf.Set(msg.From) - } - - sm.eth.EventMux().Post(state.Manifest().Messages) - - return bloomf -} - -func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, err error) { - if !sm.bc.HasBlock(block.PrevHash) { - return nil, ParentError(block.PrevHash) - } - - sm.lastAttemptedBlock = block - - var ( - parent = sm.bc.GetBlock(block.PrevHash) - state = parent.State().Copy() - ) - - defer state.Reset() - - sm.ApplyDiff(state, parent, block) - - sm.AccumelateRewards(state, block, parent) - - return state.Manifest().Messages, nil -} diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go deleted file mode 100644 index ad7b320c4..000000000 --- a/ethchain/state_transition.go +++ /dev/null @@ -1,264 +0,0 @@ -package ethchain - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/vm" -) - -/* - * The State transitioning model - * - * A state transition is a change made when a transaction is applied to the current world state - * The state transitioning model does all all the necessary work to work out a valid new state root. - * 1) Nonce handling - * 2) Pre pay / buy gas of the coinbase (miner) - * 3) Create a new state object if the recipient is \0*32 - * 4) Value transfer - * == If contract creation == - * 4a) Attempt to run transaction data - * 4b) If valid, use result as code for the new state object - * == end == - * 5) Run Script section - * 6) Derive new state root - */ -type StateTransition struct { - coinbase, receiver []byte - tx *Transaction - gas, gasPrice *big.Int - value *big.Int - data []byte - state *ethstate.State - block *Block - - cb, rec, sen *ethstate.StateObject -} - -func NewStateTransition(coinbase *ethstate.StateObject, tx *Transaction, state *ethstate.State, block *Block) *StateTransition { - return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} -} - -func (self *StateTransition) Coinbase() *ethstate.StateObject { - if self.cb != nil { - return self.cb - } - - self.cb = self.state.GetOrNewStateObject(self.coinbase) - return self.cb -} -func (self *StateTransition) Sender() *ethstate.StateObject { - if self.sen != nil { - return self.sen - } - - self.sen = self.state.GetOrNewStateObject(self.tx.Sender()) - - return self.sen -} -func (self *StateTransition) Receiver() *ethstate.StateObject { - if self.tx != nil && self.tx.CreatesContract() { - return nil - } - - if self.rec != nil { - return self.rec - } - - self.rec = self.state.GetOrNewStateObject(self.tx.Recipient) - return self.rec -} - -func (self *StateTransition) UseGas(amount *big.Int) error { - if self.gas.Cmp(amount) < 0 { - return OutOfGasError() - } - self.gas.Sub(self.gas, amount) - - return nil -} - -func (self *StateTransition) AddGas(amount *big.Int) { - self.gas.Add(self.gas, amount) -} - -func (self *StateTransition) BuyGas() error { - var err error - - sender := self.Sender() - if sender.Balance().Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance()) - } - - coinbase := self.Coinbase() - err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) - if err != nil { - return err - } - - self.AddGas(self.tx.Gas) - sender.SubAmount(self.tx.GasValue()) - - return nil -} - -func (self *StateTransition) RefundGas() { - coinbase, sender := self.Coinbase(), self.Sender() - coinbase.RefundGas(self.gas, self.tx.GasPrice) - - // Return remaining gas - remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice) - sender.AddAmount(remaining) -} - -func (self *StateTransition) preCheck() (err error) { - var ( - tx = self.tx - sender = self.Sender() - ) - - // Make sure this transaction's nonce is correct - if sender.Nonce != tx.Nonce { - return NonceError(tx.Nonce, sender.Nonce) - } - - // Pre-pay gas / Buy gas of the coinbase account - if err = self.BuyGas(); err != nil { - return err - } - - return nil -} - -func (self *StateTransition) TransitionState() (err error) { - statelogger.Debugf("(~) %x\n", self.tx.Hash()) - - // XXX Transactions after this point are considered valid. - if err = self.preCheck(); err != nil { - return - } - - var ( - tx = self.tx - sender = self.Sender() - receiver *ethstate.StateObject - ) - - defer self.RefundGas() - - // Increment the nonce for the next transaction - sender.Nonce += 1 - - // Transaction gas - if err = self.UseGas(vm.GasTx); err != nil { - return - } - - // Pay data gas - dataPrice := big.NewInt(int64(len(self.data))) - dataPrice.Mul(dataPrice, vm.GasData) - if err = self.UseGas(dataPrice); err != nil { - return - } - - if sender.Balance().Cmp(self.value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) - } - - var snapshot *ethstate.State - // If the receiver is nil it's a contract (\0*32). - if tx.CreatesContract() { - // Subtract the (irreversible) amount from the senders account - sender.SubAmount(self.value) - - snapshot = self.state.Copy() - - // Create a new state object for the contract - receiver = MakeContract(tx, self.state) - self.rec = receiver - if receiver == nil { - return fmt.Errorf("Unable to create contract") - } - - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.value) - } else { - receiver = self.Receiver() - - // Subtract the amount from the senders account - sender.SubAmount(self.value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.value) - - snapshot = self.state.Copy() - } - - msg := self.state.Manifest().AddMessage(ðstate.Message{ - To: receiver.Address(), From: sender.Address(), - Input: self.tx.Data, - Origin: sender.Address(), - Block: self.block.Hash(), Timestamp: self.block.Time, Coinbase: self.block.Coinbase, Number: self.block.Number, - Value: self.value, - }) - - // Process the init code and create 'valid' contract - if IsContractAddr(self.receiver) { - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - self.data = nil - - code, evmerr := self.Eval(msg, receiver.Init(), receiver) - if evmerr != nil { - self.state.Set(snapshot) - - statelogger.Debugf("Error during init execution %v", evmerr) - } - - receiver.Code = code - msg.Output = code - } else { - if len(receiver.Code) > 0 { - ret, evmerr := self.Eval(msg, receiver.Code, receiver) - if evmerr != nil { - self.state.Set(snapshot) - - statelogger.Debugf("Error during code execution %v", evmerr) - } - - msg.Output = ret - } else { - // Add default LOG. Default = big(sender.addr) + 1 - addr := ethutil.BigD(receiver.Address()) - self.state.AddLog(ethstate.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) - } - } - - return -} - -func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject) (ret []byte, err error) { - var ( - transactor = self.Sender() - state = self.state - env = NewEnv(state, self.tx, self.block) - callerClosure = vm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) - ) - - evm := vm.New(env, vm.DebugVmTy) - ret, _, err = callerClosure.Call(evm, self.tx.Data) - - return -} - -// Converts an transaction in to a state object -func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject { - addr := tx.CreationAddress(state) - - contract := state.GetOrNewStateObject(addr) - contract.InitCode = tx.Data - - return contract -} diff --git a/ethchain/transaction.go b/ethchain/transaction.go deleted file mode 100644 index 331f44b55..000000000 --- a/ethchain/transaction.go +++ /dev/null @@ -1,271 +0,0 @@ -package ethchain - -import ( - "bytes" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/obscuren/secp256k1-go" -) - -var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - -func IsContractAddr(addr []byte) bool { - return len(addr) == 0 - //return bytes.Compare(addr, ContractAddr) == 0 -} - -type Transaction struct { - Nonce uint64 - Recipient []byte - Value *big.Int - Gas *big.Int - GasPrice *big.Int - Data []byte - v byte - r, s []byte - - // Indicates whether this tx is a contract creation transaction - contractCreation bool -} - -func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} -} - -func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)} -} - -func NewTransactionFromBytes(data []byte) *Transaction { - tx := &Transaction{} - tx.RlpDecode(data) - - return tx -} - -func NewTransactionFromValue(val *ethutil.Value) *Transaction { - tx := &Transaction{} - tx.RlpValueDecode(val) - - return tx -} - -func (self *Transaction) GasValue() *big.Int { - return new(big.Int).Mul(self.Gas, self.GasPrice) -} - -func (self *Transaction) TotalValue() *big.Int { - v := self.GasValue() - return v.Add(v, self.Value) -} - -func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - - return ethcrypto.Sha3(ethutil.NewValue(data).Encode()) -} - -func (tx *Transaction) CreatesContract() bool { - return tx.contractCreation -} - -/* Deprecated */ -func (tx *Transaction) IsContract() bool { - return tx.CreatesContract() -} - -func (tx *Transaction) CreationAddress(state *ethstate.State) []byte { - // Generate a new address - addr := ethcrypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] - //for i := uint64(0); state.GetStateObject(addr) != nil; i++ { - // addr = ethcrypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] - //} - - return addr -} - -func (tx *Transaction) Signature(key []byte) []byte { - hash := tx.Hash() - - sig, _ := secp256k1.Sign(hash, key) - - return sig -} - -func (tx *Transaction) PublicKey() []byte { - hash := tx.Hash() - - // TODO - r := ethutil.LeftPadBytes(tx.r, 32) - s := ethutil.LeftPadBytes(tx.s, 32) - - sig := append(r, s...) - sig = append(sig, tx.v-27) - - pubkey := ethcrypto.Ecrecover(append(hash, sig...)) - //pubkey, _ := secp256k1.RecoverPubkey(hash, sig) - - return pubkey -} - -func (tx *Transaction) Sender() []byte { - pubkey := tx.PublicKey() - - // Validate the returned key. - // Return nil if public key isn't in full format - if pubkey[0] != 4 { - return nil - } - - return ethcrypto.Sha3(pubkey[1:])[12:] -} - -func (tx *Transaction) Sign(privk []byte) error { - - sig := tx.Signature(privk) - - tx.r = sig[:32] - tx.s = sig[32:64] - tx.v = sig[64] + 27 - - return nil -} - -func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - - // TODO Remove prefixing zero's - - return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes()) -} - -func (tx *Transaction) RlpValue() *ethutil.Value { - return ethutil.NewValue(tx.RlpData()) -} - -func (tx *Transaction) RlpEncode() []byte { - return tx.RlpValue().Encode() -} - -func (tx *Transaction) RlpDecode(data []byte) { - tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) -} - -func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { - tx.Nonce = decoder.Get(0).Uint() - tx.GasPrice = decoder.Get(1).BigInt() - tx.Gas = decoder.Get(2).BigInt() - tx.Recipient = decoder.Get(3).Bytes() - tx.Value = decoder.Get(4).BigInt() - tx.Data = decoder.Get(5).Bytes() - tx.v = byte(decoder.Get(6).Uint()) - - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() - - if IsContractAddr(tx.Recipient) { - tx.contractCreation = true - } -} - -func (tx *Transaction) String() string { - return fmt.Sprintf(` - TX(%x) - Contract: %v - From: %x - To: %x - Nonce: %v - GasPrice: %v - Gas: %v - Value: %v - Data: 0x%x - V: 0x%x - R: 0x%x - S: 0x%x - `, - tx.Hash(), - len(tx.Recipient) == 0, - tx.Sender(), - tx.Recipient, - tx.Nonce, - tx.GasPrice, - tx.Gas, - tx.Value, - tx.Data, - tx.v, - tx.r, - tx.s) -} - -type Receipt struct { - PostState []byte - CumulativeGasUsed *big.Int - Bloom []byte - logs ethstate.Logs -} - -func NewRecieptFromValue(val *ethutil.Value) *Receipt { - r := &Receipt{} - r.RlpValueDecode(val) - - return r -} - -func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { - self.PostState = decoder.Get(0).Bytes() - self.CumulativeGasUsed = decoder.Get(1).BigInt() - self.Bloom = decoder.Get(2).Bytes() - - it := decoder.Get(3).NewIterator() - for it.Next() { - self.logs = append(self.logs, ethstate.NewLogFromValue(it.Value())) - } -} - -func (self *Receipt) RlpData() interface{} { - return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} -} - -func (self *Receipt) RlpEncode() []byte { - return ethutil.Encode(self.RlpData()) -} - -func (self *Receipt) Cmp(other *Receipt) bool { - if bytes.Compare(self.PostState, other.PostState) != 0 { - return false - } - - return true -} - -type Receipts []*Receipt - -func (self Receipts) Len() int { return len(self) } -func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) } - -// Transaction slice type for basic sorting -type Transactions []*Transaction - -func (self Transactions) RlpData() interface{} { - // Marshal the transactions of this block - enc := make([]interface{}, len(self)) - for i, tx := range self { - // Cast it to a string (safe) - enc[i] = tx.RlpData() - } - - return enc -} -func (s Transactions) Len() int { return len(s) } -func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) } - -type TxByNonce struct{ Transactions } - -func (s TxByNonce) Less(i, j int) bool { - return s.Transactions[i].Nonce < s.Transactions[j].Nonce -} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go deleted file mode 100644 index 7bd3e9ffd..000000000 --- a/ethchain/transaction_pool.go +++ /dev/null @@ -1,245 +0,0 @@ -package ethchain - -import ( - "bytes" - "container/list" - "fmt" - "math/big" - "sync" - - "github.com/ethereum/go-ethereum/ethlog" - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethwire" -) - -var txplogger = ethlog.NewLogger("TXP") - -const txPoolQueueSize = 50 - -type TxPoolHook chan *Transaction -type TxMsgTy byte - -const ( - minGasPrice = 1000000 -) - -var MinGasPrice = big.NewInt(10000000000000) - -type TxMsg struct { - Tx *Transaction - Type TxMsgTy -} - -func EachTx(pool *list.List, it func(*Transaction, *list.Element) bool) { - for e := pool.Front(); e != nil; e = e.Next() { - if it(e.Value.(*Transaction), e) { - break - } - } -} - -func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { - for e := pool.Front(); e != nil; e = e.Next() { - if tx, ok := e.Value.(*Transaction); ok { - if finder(tx, e) { - return tx - } - } - } - - return nil -} - -type TxProcessor interface { - ProcessTransaction(tx *Transaction) -} - -// The tx pool a thread safe transaction pool handler. In order to -// guarantee a non blocking pool we use a queue channel which can be -// independently read without needing access to the actual pool. If the -// pool is being drained or synced for whatever reason the transactions -// will simple queue up and handled when the mutex is freed. -type TxPool struct { - Ethereum EthManager - // The mutex for accessing the Tx pool. - mutex sync.Mutex - // Queueing channel for reading and writing incoming - // transactions to - queueChan chan *Transaction - // Quiting channel - quit chan bool - // The actual pool - pool *list.List - - SecondaryProcessor TxProcessor - - subscribers []chan TxMsg -} - -func NewTxPool(ethereum EthManager) *TxPool { - return &TxPool{ - pool: list.New(), - queueChan: make(chan *Transaction, txPoolQueueSize), - quit: make(chan bool), - Ethereum: ethereum, - } -} - -// Blocking function. Don't use directly. Use QueueTransaction instead -func (pool *TxPool) addTransaction(tx *Transaction) { - pool.mutex.Lock() - defer pool.mutex.Unlock() - - pool.pool.PushBack(tx) - - // Broadcast the transaction to the rest of the peers - pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) -} - -func (pool *TxPool) ValidateTransaction(tx *Transaction) error { - // Get the last block so we can retrieve the sender and receiver from - // the merkle trie - block := pool.Ethereum.ChainManager().CurrentBlock - // Something has gone horribly wrong if this happens - if block == nil { - return fmt.Errorf("[TXPL] No last block on the block chain") - } - - if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 { - return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) - } - - if tx.GasPrice.Cmp(MinGasPrice) < 0 { - return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice) - } - - // Get the sender - //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) - sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) - - totAmount := new(big.Int).Set(tx.Value) - // Make sure there's enough in the sender's account. Having insufficient - // funds won't invalidate this transaction but simple ignores it. - if sender.Balance().Cmp(totAmount) < 0 { - return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - } - - if tx.IsContract() { - if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { - return fmt.Errorf("[TXPL] Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) - } - } - - // Increment the nonce making each tx valid only once to prevent replay - // attacks - - return nil -} - -func (pool *TxPool) queueHandler() { -out: - for { - select { - case tx := <-pool.queueChan: - hash := tx.Hash() - foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { - return bytes.Compare(tx.Hash(), hash) == 0 - }) - - if foundTx != nil { - break - } - - // Validate the transaction - err := pool.ValidateTransaction(tx) - if err != nil { - txplogger.Debugln("Validating Tx failed", err) - } else { - // Call blocking version. - pool.addTransaction(tx) - - tmp := make([]byte, 4) - copy(tmp, tx.Recipient) - - txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) - - // Notify the subscribers - pool.Ethereum.EventMux().Post(TxPreEvent{tx}) - } - case <-pool.quit: - break out - } - } -} - -func (pool *TxPool) QueueTransaction(tx *Transaction) { - pool.queueChan <- tx -} - -func (pool *TxPool) CurrentTransactions() []*Transaction { - pool.mutex.Lock() - defer pool.mutex.Unlock() - - txList := make([]*Transaction, pool.pool.Len()) - i := 0 - for e := pool.pool.Front(); e != nil; e = e.Next() { - tx := e.Value.(*Transaction) - - txList[i] = tx - - i++ - } - - return txList -} - -func (pool *TxPool) RemoveInvalid(state *ethstate.State) { - pool.mutex.Lock() - defer pool.mutex.Unlock() - - for e := pool.pool.Front(); e != nil; e = e.Next() { - tx := e.Value.(*Transaction) - sender := state.GetAccount(tx.Sender()) - err := pool.ValidateTransaction(tx) - if err != nil || sender.Nonce >= tx.Nonce { - pool.pool.Remove(e) - } - } -} - -func (self *TxPool) RemoveSet(txs Transactions) { - self.mutex.Lock() - defer self.mutex.Unlock() - - for _, tx := range txs { - EachTx(self.pool, func(t *Transaction, element *list.Element) bool { - if t == tx { - self.pool.Remove(element) - return true // To stop the loop - } - return false - }) - } -} - -func (pool *TxPool) Flush() []*Transaction { - txList := pool.CurrentTransactions() - - // Recreate a new list all together - // XXX Is this the fastest way? - pool.pool = list.New() - - return txList -} - -func (pool *TxPool) Start() { - go pool.queueHandler() -} - -func (pool *TxPool) Stop() { - close(pool.quit) - - pool.Flush() - - txplogger.Infoln("Stopped") -} diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go deleted file mode 100644 index 3603fd8a7..000000000 --- a/ethchain/transaction_test.go +++ /dev/null @@ -1 +0,0 @@ -package ethchain diff --git a/ethchain/types.go b/ethchain/types.go deleted file mode 100644 index d0e7fcfb0..000000000 --- a/ethchain/types.go +++ /dev/null @@ -1,312 +0,0 @@ -package ethchain - -import ( - "fmt" -) - -type OpCode int - -// Op codes -const ( - // 0x0 range - arithmetic ops - STOP = 0x00 - ADD = 0x01 - MUL = 0x02 - SUB = 0x03 - DIV = 0x04 - SDIV = 0x05 - MOD = 0x06 - SMOD = 0x07 - EXP = 0x08 - BNOT = 0x09 - LT = 0x0a - GT = 0x0b - SLT = 0x0c - SGT = 0x0d - EQ = 0x0e - NOT = 0x0f - - // 0x10 range - bit ops - AND = 0x10 - OR = 0x11 - XOR = 0x12 - BYTE = 0x13 - ADDMOD = 0x14 - MULMOD = 0x15 - - // 0x20 range - crypto - SHA3 = 0x20 - - // 0x30 range - closure state - ADDRESS = 0x30 - BALANCE = 0x31 - ORIGIN = 0x32 - CALLER = 0x33 - CALLVALUE = 0x34 - CALLDATALOAD = 0x35 - CALLDATASIZE = 0x36 - CALLDATACOPY = 0x37 - CODESIZE = 0x38 - CODECOPY = 0x39 - GASPRICE = 0x3a - EXTCODESIZE = 0x3b - EXTCODECOPY = 0x3c - - // 0x40 range - block operations - PREVHASH = 0x40 - COINBASE = 0x41 - TIMESTAMP = 0x42 - NUMBER = 0x43 - DIFFICULTY = 0x44 - GASLIMIT = 0x45 - - // 0x50 range - 'storage' and execution - POP = 0x50 - //DUP = 0x51 - //SWAP = 0x52 - MLOAD = 0x53 - MSTORE = 0x54 - MSTORE8 = 0x55 - SLOAD = 0x56 - SSTORE = 0x57 - JUMP = 0x58 - JUMPI = 0x59 - PC = 0x5a - MSIZE = 0x5b - GAS = 0x5c - - // 0x60 range - PUSH1 = 0x60 - PUSH2 = 0x61 - PUSH3 = 0x62 - PUSH4 = 0x63 - PUSH5 = 0x64 - PUSH6 = 0x65 - PUSH7 = 0x66 - PUSH8 = 0x67 - PUSH9 = 0x68 - PUSH10 = 0x69 - PUSH11 = 0x6a - PUSH12 = 0x6b - PUSH13 = 0x6c - PUSH14 = 0x6d - PUSH15 = 0x6e - PUSH16 = 0x6f - PUSH17 = 0x70 - PUSH18 = 0x71 - PUSH19 = 0x72 - PUSH20 = 0x73 - PUSH21 = 0x74 - PUSH22 = 0x75 - PUSH23 = 0x76 - PUSH24 = 0x77 - PUSH25 = 0x78 - PUSH26 = 0x79 - PUSH27 = 0x7a - PUSH28 = 0x7b - PUSH29 = 0x7c - PUSH30 = 0x7d - PUSH31 = 0x7e - PUSH32 = 0x7f - - DUP1 = 0x80 - DUP2 = 0x81 - DUP3 = 0x82 - DUP4 = 0x83 - DUP5 = 0x84 - DUP6 = 0x85 - DUP7 = 0x86 - DUP8 = 0x87 - DUP9 = 0x88 - DUP10 = 0x89 - DUP11 = 0x8a - DUP12 = 0x8b - DUP13 = 0x8c - DUP14 = 0x8d - DUP15 = 0x8e - DUP16 = 0x8f - - SWAP1 = 0x90 - SWAP2 = 0x91 - SWAP3 = 0x92 - SWAP4 = 0x93 - SWAP5 = 0x94 - SWAP6 = 0x95 - SWAP7 = 0x96 - SWAP8 = 0x97 - SWAP9 = 0x98 - SWAP10 = 0x99 - SWAP11 = 0x9a - SWAP12 = 0x9b - SWAP13 = 0x9c - SWAP14 = 0x9d - SWAP15 = 0x9e - SWAP16 = 0x9f - - // 0xf0 range - closures - CREATE = 0xf0 - CALL = 0xf1 - RETURN = 0xf2 - CALLCODE = 0xf3 - - // 0x70 range - other - LOG = 0xfe // XXX Unofficial - SUICIDE = 0xff -) - -// Since the opcodes aren't all in order we can't use a regular slice -var opCodeToString = map[OpCode]string{ - // 0x0 range - arithmetic ops - STOP: "STOP", - ADD: "ADD", - MUL: "MUL", - SUB: "SUB", - DIV: "DIV", - SDIV: "SDIV", - MOD: "MOD", - SMOD: "SMOD", - EXP: "EXP", - BNOT: "BNOT", - LT: "LT", - GT: "GT", - SLT: "SLT", - SGT: "SGT", - EQ: "EQ", - NOT: "NOT", - - // 0x10 range - bit ops - AND: "AND", - OR: "OR", - XOR: "XOR", - BYTE: "BYTE", - ADDMOD: "ADDMOD", - MULMOD: "MULMOD", - - // 0x20 range - crypto - SHA3: "SHA3", - - // 0x30 range - closure state - ADDRESS: "ADDRESS", - BALANCE: "BALANCE", - ORIGIN: "ORIGIN", - CALLER: "CALLER", - CALLVALUE: "CALLVALUE", - CALLDATALOAD: "CALLDATALOAD", - CALLDATASIZE: "CALLDATASIZE", - CALLDATACOPY: "CALLDATACOPY", - CODESIZE: "CODESIZE", - CODECOPY: "CODECOPY", - GASPRICE: "TXGASPRICE", - - // 0x40 range - block operations - PREVHASH: "PREVHASH", - COINBASE: "COINBASE", - TIMESTAMP: "TIMESTAMP", - NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", - GASLIMIT: "GASLIMIT", - EXTCODESIZE: "EXTCODESIZE", - EXTCODECOPY: "EXTCODECOPY", - - // 0x50 range - 'storage' and execution - POP: "POP", - //DUP: "DUP", - //SWAP: "SWAP", - MLOAD: "MLOAD", - MSTORE: "MSTORE", - MSTORE8: "MSTORE8", - SLOAD: "SLOAD", - SSTORE: "SSTORE", - JUMP: "JUMP", - JUMPI: "JUMPI", - PC: "PC", - MSIZE: "MSIZE", - GAS: "GAS", - - // 0x60 range - push - PUSH1: "PUSH1", - PUSH2: "PUSH2", - PUSH3: "PUSH3", - PUSH4: "PUSH4", - PUSH5: "PUSH5", - PUSH6: "PUSH6", - PUSH7: "PUSH7", - PUSH8: "PUSH8", - PUSH9: "PUSH9", - PUSH10: "PUSH10", - PUSH11: "PUSH11", - PUSH12: "PUSH12", - PUSH13: "PUSH13", - PUSH14: "PUSH14", - PUSH15: "PUSH15", - PUSH16: "PUSH16", - PUSH17: "PUSH17", - PUSH18: "PUSH18", - PUSH19: "PUSH19", - PUSH20: "PUSH20", - PUSH21: "PUSH21", - PUSH22: "PUSH22", - PUSH23: "PUSH23", - PUSH24: "PUSH24", - PUSH25: "PUSH25", - PUSH26: "PUSH26", - PUSH27: "PUSH27", - PUSH28: "PUSH28", - PUSH29: "PUSH29", - PUSH30: "PUSH30", - PUSH31: "PUSH31", - PUSH32: "PUSH32", - - DUP1: "DUP1", - DUP2: "DUP2", - DUP3: "DUP3", - DUP4: "DUP4", - DUP5: "DUP5", - DUP6: "DUP6", - DUP7: "DUP7", - DUP8: "DUP8", - DUP9: "DUP9", - DUP10: "DUP10", - DUP11: "DUP11", - DUP12: "DUP12", - DUP13: "DUP13", - DUP14: "DUP14", - DUP15: "DUP15", - DUP16: "DUP16", - - SWAP1: "SWAP1", - SWAP2: "SWAP2", - SWAP3: "SWAP3", - SWAP4: "SWAP4", - SWAP5: "SWAP5", - SWAP6: "SWAP6", - SWAP7: "SWAP7", - SWAP8: "SWAP8", - SWAP9: "SWAP9", - SWAP10: "SWAP10", - SWAP11: "SWAP11", - SWAP12: "SWAP12", - SWAP13: "SWAP13", - SWAP14: "SWAP14", - SWAP15: "SWAP15", - SWAP16: "SWAP16", - - // 0xf0 range - CREATE: "CREATE", - CALL: "CALL", - RETURN: "RETURN", - CALLCODE: "CALLCODE", - - // 0x70 range - other - LOG: "LOG", - SUICIDE: "SUICIDE", -} - -func (o OpCode) String() string { - str := opCodeToString[o] - if len(str) == 0 { - return fmt.Sprintf("Missing opcode 0x%x", int(o)) - } - - return str -} diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go deleted file mode 100644 index 1bb67dbd0..000000000 --- a/ethchain/vm_env.go +++ /dev/null @@ -1,39 +0,0 @@ -package ethchain - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/vm" -) - -type VMEnv struct { - state *ethstate.State - block *Block - tx *Transaction -} - -func NewEnv(state *ethstate.State, tx *Transaction, block *Block) *VMEnv { - return &VMEnv{ - state: state, - block: block, - tx: tx, - } -} - -func (self *VMEnv) Origin() []byte { return self.tx.Sender() } -func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number } -func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } -func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } -func (self *VMEnv) Time() int64 { return self.block.Time } -func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } -func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } -func (self *VMEnv) Value() *big.Int { return self.tx.Value } -func (self *VMEnv) State() *ethstate.State { return self.state } -func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } -func (self *VMEnv) AddLog(log ethstate.Log) { - self.state.AddLog(log) -} -func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { - return vm.Transfer(from, to, amount) -} diff --git a/ethereum.go b/ethereum.go index a389c663d..489e88b8a 100644 --- a/ethereum.go +++ b/ethereum.go @@ -14,7 +14,7 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethcrypto" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethstate" @@ -50,12 +50,12 @@ type Ethereum struct { // DB interface db ethutil.Database // State manager for processing new blocks and managing the over all states - stateManager *ethchain.StateManager + stateManager *chain.StateManager // The transaction pool. Transaction can be pushed on this pool // for later including in the blocks - txPool *ethchain.TxPool + txPool *chain.TxPool // The canonical chain - blockChain *ethchain.ChainManager + blockChain *chain.ChainManager // The block pool blockPool *BlockPool // Eventer @@ -94,7 +94,7 @@ type Ethereum struct { filterMu sync.RWMutex filterId int - filters map[int]*ethchain.Filter + filters map[int]*chain.Filter } func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { @@ -124,13 +124,13 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager keyManager: keyManager, clientIdentity: clientIdentity, isUpToDate: true, - filters: make(map[int]*ethchain.Filter), + filters: make(map[int]*chain.Filter), } ethereum.blockPool = NewBlockPool(ethereum) - ethereum.txPool = ethchain.NewTxPool(ethereum) - ethereum.blockChain = ethchain.NewChainManager(ethereum) - ethereum.stateManager = ethchain.NewStateManager(ethereum) + ethereum.txPool = chain.NewTxPool(ethereum) + ethereum.blockChain = chain.NewChainManager(ethereum) + ethereum.stateManager = chain.NewStateManager(ethereum) // Start the tx pool ethereum.txPool.Start() @@ -146,15 +146,15 @@ func (s *Ethereum) ClientIdentity() ethwire.ClientIdentity { return s.clientIdentity } -func (s *Ethereum) ChainManager() *ethchain.ChainManager { +func (s *Ethereum) ChainManager() *chain.ChainManager { return s.blockChain } -func (s *Ethereum) StateManager() *ethchain.StateManager { +func (s *Ethereum) StateManager() *chain.StateManager { return s.stateManager } -func (s *Ethereum) TxPool() *ethchain.TxPool { +func (s *Ethereum) TxPool() *chain.TxPool { return s.txPool } func (s *Ethereum) BlockPool() *BlockPool { @@ -590,7 +590,7 @@ out: // InstallFilter adds filter for blockchain events. // The filter's callbacks will run for matching blocks and messages. // The filter should not be modified after it has been installed. -func (self *Ethereum) InstallFilter(filter *ethchain.Filter) (id int) { +func (self *Ethereum) InstallFilter(filter *chain.Filter) (id int) { self.filterMu.Lock() id = self.filterId self.filters[id] = filter @@ -607,7 +607,7 @@ func (self *Ethereum) UninstallFilter(id int) { // GetFilter retrieves a filter installed using InstallFilter. // The filter may not be modified. -func (self *Ethereum) GetFilter(id int) *ethchain.Filter { +func (self *Ethereum) GetFilter(id int) *chain.Filter { self.filterMu.RLock() defer self.filterMu.RUnlock() return self.filters[id] @@ -615,10 +615,10 @@ func (self *Ethereum) GetFilter(id int) *ethchain.Filter { func (self *Ethereum) filterLoop() { // Subscribe to events - events := self.eventMux.Subscribe(ethchain.NewBlockEvent{}, ethstate.Messages(nil)) + events := self.eventMux.Subscribe(chain.NewBlockEvent{}, ethstate.Messages(nil)) for event := range events.Chan() { switch event := event.(type) { - case ethchain.NewBlockEvent: + case chain.NewBlockEvent: self.filterMu.RLock() for _, filter := range self.filters { if filter.BlockCallback != nil { diff --git a/ethminer/miner.go b/ethminer/miner.go index 571b92ce0..c2e973f32 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -4,7 +4,7 @@ import ( "bytes" "sort" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethwire" "github.com/ethereum/go-ethereum/event" @@ -13,12 +13,12 @@ import ( var logger = ethlog.NewLogger("MINER") type Miner struct { - pow ethchain.PoW - ethereum ethchain.EthManager + pow chain.PoW + ethereum chain.EthManager coinbase []byte - txs ethchain.Transactions - uncles []*ethchain.Block - block *ethchain.Block + txs chain.Transactions + uncles []*chain.Block + block *chain.Block events event.Subscription powQuitChan chan struct{} @@ -37,13 +37,13 @@ type Event struct { Miner *Miner } -func (self *Miner) GetPow() ethchain.PoW { +func (self *Miner) GetPow() chain.PoW { return self.pow } -func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) *Miner { +func NewDefaultMiner(coinbase []byte, ethereum chain.EthManager) *Miner { miner := Miner{ - pow: ðchain.EasyPow{}, + pow: &chain.EasyPow{}, ethereum: ethereum, coinbase: coinbase, } @@ -64,7 +64,7 @@ func (miner *Miner) Start() { miner.block = miner.ethereum.ChainManager().NewBlock(miner.coinbase) mux := miner.ethereum.EventMux() - miner.events = mux.Subscribe(ethchain.NewBlockEvent{}, ethchain.TxPreEvent{}) + miner.events = mux.Subscribe(chain.NewBlockEvent{}, chain.TxPreEvent{}) // Prepare inital block //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) @@ -87,7 +87,7 @@ func (miner *Miner) listener() { select { case event := <-miner.events.Chan(): switch event := event.(type) { - case ethchain.NewBlockEvent: + case chain.NewBlockEvent: miner.stopMining() block := event.Block @@ -97,7 +97,7 @@ func (miner *Miner) listener() { //logger.Infoln("New top block found resetting state") // Filter out which Transactions we have that were not in this block - var newtxs []*ethchain.Transaction + var newtxs []*chain.Transaction for _, tx := range miner.txs { found := false for _, othertx := range block.Transactions() { @@ -118,7 +118,7 @@ func (miner *Miner) listener() { } miner.startMining() - case ethchain.TxPreEvent: + case chain.TxPreEvent: miner.stopMining() found := false @@ -171,7 +171,7 @@ func (self *Miner) mineNewBlock() { } // Sort the transactions by nonce in case of odd network propagation - sort.Sort(ethchain.TxByNonce{self.txs}) + sort.Sort(chain.TxByNonce{self.txs}) // Accumulate all valid transactions and apply them to the new state // Error may be ignored. It's not important during mining @@ -208,7 +208,7 @@ func (self *Miner) mineNewBlock() { logger.Infoln(self.block) // Gather the new batch of transactions currently in the tx pool self.txs = self.ethereum.TxPool().CurrentTransactions() - self.ethereum.EventMux().Post(ethchain.NewBlockEvent{self.block}) + self.ethereum.EventMux().Post(chain.NewBlockEvent{self.block}) } // Continue mining on the next block diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index 4b4369768..ee4637d8f 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -5,7 +5,7 @@ import ( "encoding/json" "sync/atomic" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethcrypto" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" @@ -15,7 +15,7 @@ type JSPipe struct { *Pipe } -func NewJSPipe(eth ethchain.EthManager) *JSPipe { +func NewJSPipe(eth chain.EthManager) *JSPipe { return &JSPipe{New(eth)} } @@ -63,7 +63,7 @@ func (self *JSPipe) PeerCount() int { func (self *JSPipe) Peers() []JSPeer { var peers []JSPeer for peer := self.obj.Peers().Front(); peer != nil; peer = peer.Next() { - p := peer.Value.(ethchain.Peer) + p := peer.Value.(chain.Peer) // we only want connected peers if atomic.LoadInt32(p.Connected()) != 0 { peers = append(peers, *NewJSPeer(p)) @@ -209,7 +209,7 @@ func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr gas = ethutil.Big(gasStr) gasPrice = ethutil.Big(gasPriceStr) data []byte - tx *ethchain.Transaction + tx *chain.Transaction ) if ethutil.IsHex(codeStr) { @@ -219,9 +219,9 @@ func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr } if contractCreation { - tx = ethchain.NewContractCreationTx(value, gas, gasPrice, data) + tx = chain.NewContractCreationTx(value, gas, gasPrice, data) } else { - tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, data) + tx = chain.NewTransactionMessage(hash, value, gas, gasPrice, data) } acc := self.obj.StateManager().TransState().GetOrNewStateObject(keyPair.Address()) @@ -240,7 +240,7 @@ func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr } func (self *JSPipe) PushTx(txStr string) (*JSReceipt, error) { - tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) + tx := chain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) self.obj.TxPool().QueueTransaction(tx) return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(self.World().State()), tx.Hash(), tx.Sender()), nil } diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go index 956a49ab7..94019f275 100644 --- a/ethpipe/js_types.go +++ b/ethpipe/js_types.go @@ -5,7 +5,7 @@ import ( "strconv" "strings" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethcrypto" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" @@ -14,7 +14,7 @@ import ( // Block interface exposed to QML type JSBlock struct { //Transactions string `json:"transactions"` - ref *ethchain.Block + ref *chain.Block Size string `json:"size"` Number int `json:"number"` Hash string `json:"hash"` @@ -29,7 +29,7 @@ type JSBlock struct { } // Creates a new QML Block from a chain block -func NewJSBlock(block *ethchain.Block) *JSBlock { +func NewJSBlock(block *chain.Block) *JSBlock { if block == nil { return &JSBlock{} } @@ -75,7 +75,7 @@ func (self *JSBlock) GetTransaction(hash string) *JSTransaction { } type JSTransaction struct { - ref *ethchain.Transaction + ref *chain.Transaction Value string `json:"value"` Gas string `json:"gas"` @@ -90,7 +90,7 @@ type JSTransaction struct { Confirmations int `json:"confirmations"` } -func NewJSTx(tx *ethchain.Transaction, state *ethstate.State) *JSTransaction { +func NewJSTx(tx *chain.Transaction, state *ethstate.State) *JSTransaction { hash := ethutil.Bytes2Hex(tx.Hash()) receiver := ethutil.Bytes2Hex(tx.Recipient) if receiver == "0000000000000000000000000000000000000000" { @@ -101,7 +101,7 @@ func NewJSTx(tx *ethchain.Transaction, state *ethstate.State) *JSTransaction { var data string if tx.CreatesContract() { - data = strings.Join(ethchain.Disassemble(tx.Data), "\n") + data = strings.Join(chain.Disassemble(tx.Data), "\n") } else { data = ethutil.Bytes2Hex(tx.Data) } @@ -150,7 +150,7 @@ func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) * // Peer interface exposed to QML type JSPeer struct { - ref *ethchain.Peer + ref *chain.Peer Inbound bool `json:"isInbound"` LastSend int64 `json:"lastSend"` LastPong int64 `json:"lastPong"` @@ -162,7 +162,7 @@ type JSPeer struct { Caps string `json:"caps"` } -func NewJSPeer(peer ethchain.Peer) *JSPeer { +func NewJSPeer(peer chain.Peer) *JSPeer { if peer == nil { return nil } diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index 13085c887..7dd6ae262 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethcrypto" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethstate" @@ -19,15 +19,15 @@ type VmVars struct { } type Pipe struct { - obj ethchain.EthManager - stateManager *ethchain.StateManager - blockChain *ethchain.ChainManager + obj chain.EthManager + stateManager *chain.StateManager + blockChain *chain.ChainManager world *World Vm VmVars } -func New(obj ethchain.EthManager) *Pipe { +func New(obj chain.EthManager) *Pipe { pipe := &Pipe{ obj: obj, stateManager: obj.StateManager(), @@ -68,7 +68,7 @@ func (self *Pipe) ExecuteObject(object *Object, data []byte, value, gas, price * return ret, err } -func (self *Pipe) Block(hash []byte) *ethchain.Block { +func (self *Pipe) Block(hash []byte) *chain.Block { return self.blockChain.GetBlock(hash) } @@ -111,7 +111,7 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price contractCreation = true } - var tx *ethchain.Transaction + var tx *chain.Transaction // Compile and assemble the given data if contractCreation { script, err := ethutil.Compile(string(data), false) @@ -119,7 +119,7 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price return nil, err } - tx = ethchain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), script) + tx = chain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), script) } else { data := ethutil.StringToByteFunc(string(data), func(s string) (ret []byte) { slice := strings.Split(s, "\n") @@ -130,7 +130,7 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price return }) - tx = ethchain.NewTransactionMessage(hash, value.BigInt(), gas.BigInt(), price.BigInt(), data) + tx = chain.NewTransactionMessage(hash, value.BigInt(), gas.BigInt(), price.BigInt(), data) } acc := self.stateManager.TransState().GetOrNewStateObject(key.Address()) @@ -151,7 +151,7 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price return tx.Hash(), nil } -func (self *Pipe) PushTx(tx *ethchain.Transaction) ([]byte, error) { +func (self *Pipe) PushTx(tx *chain.Transaction) ([]byte, error) { self.obj.TxPool().QueueTransaction(tx) if tx.Recipient == nil { addr := tx.CreationAddress(self.World().State()) diff --git a/ethpipe/vm_env.go b/ethpipe/vm_env.go index eb1190cf1..baab67b28 100644 --- a/ethpipe/vm_env.go +++ b/ethpipe/vm_env.go @@ -3,19 +3,19 @@ package ethpipe import ( "math/big" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/vm" ) type VMEnv struct { state *ethstate.State - block *ethchain.Block + block *chain.Block value *big.Int sender []byte } -func NewEnv(state *ethstate.State, block *ethchain.Block, value *big.Int, sender []byte) *VMEnv { +func NewEnv(state *ethstate.State, block *chain.Block, value *big.Int, sender []byte) *VMEnv { return &VMEnv{ state: state, block: block, diff --git a/javascript/javascript_runtime.go b/javascript/javascript_runtime.go index 6c5a87338..36850021d 100644 --- a/javascript/javascript_runtime.go +++ b/javascript/javascript_runtime.go @@ -8,7 +8,7 @@ import ( "path/filepath" "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethpipe" "github.com/ethereum/go-ethereum/ethstate" @@ -62,7 +62,7 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE { // Subscribe to events mux := ethereum.EventMux() - re.events = mux.Subscribe(ethchain.NewBlockEvent{}) + re.events = mux.Subscribe(chain.NewBlockEvent{}) // We have to make sure that, whoever calls this, calls "Stop" go re.mainLoop() @@ -130,7 +130,7 @@ func (self *JSRE) dump(call otto.FunctionCall) otto.Value { var state *ethstate.State if len(call.ArgumentList) > 0 { - var block *ethchain.Block + var block *chain.Block if call.Argument(0).IsNumber() { num, _ := call.Argument(0).ToInteger() block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num)) diff --git a/peer.go b/peer.go index 31bee1937..ab25e5709 100644 --- a/peer.go +++ b/peer.go @@ -12,7 +12,7 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethwire" @@ -155,7 +155,7 @@ type Peer struct { pingTime time.Duration pingStartTime time.Time - lastRequestedBlock *ethchain.Block + lastRequestedBlock *chain.Block protocolCaps *ethutil.Value } @@ -378,7 +378,7 @@ func formatMessage(msg *ethwire.Msg) (ret string) { case ethwire.MsgPeersTy: ret += fmt.Sprintf("(%d entries)", msg.Data.Len()) case ethwire.MsgBlockTy: - b1, b2 := ethchain.NewBlockFromRlpValue(msg.Data.Get(0)), ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len()-1)) + b1, b2 := chain.NewBlockFromRlpValue(msg.Data.Get(0)), ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len()-1)) ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), b1.Hash()[0:4], b2.Hash()[0:4]) case ethwire.MsgBlockHashesTy: h1, h2 := msg.Data.Get(0).Bytes(), msg.Data.Get(msg.Data.Len()-1).Bytes() @@ -429,7 +429,7 @@ func (p *Peer) HandleInbound() { // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Len(); i++ { - tx := ethchain.NewTransactionFromValue(msg.Data.Get(i)) + tx := chain.NewTransactionFromValue(msg.Data.Get(i)) p.ethereum.TxPool().QueueTransaction(tx) } case ethwire.MsgGetPeersTy: @@ -535,7 +535,7 @@ func (p *Peer) HandleInbound() { it := msg.Data.NewIterator() for it.Next() { - block := ethchain.NewBlockFromRlpValue(it.Value()) + block := chain.NewBlockFromRlpValue(it.Value()) blockPool.Add(block, p) p.lastBlockReceived = time.Now() @@ -543,7 +543,7 @@ func (p *Peer) HandleInbound() { case ethwire.MsgNewBlockTy: var ( blockPool = p.ethereum.blockPool - block = ethchain.NewBlockFromRlpValue(msg.Data.Get(0)) + block = chain.NewBlockFromRlpValue(msg.Data.Get(0)) td = msg.Data.Get(1).BigInt() ) diff --git a/ui/filter.go b/ui/filter.go index ad29abbc5..84209861e 100644 --- a/ui/filter.go +++ b/ui/filter.go @@ -1,12 +1,12 @@ package ui import ( - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethutil" ) -func NewFilterFromMap(object map[string]interface{}, eth ethchain.EthManager) *ethchain.Filter { - filter := ethchain.NewFilter(eth) +func NewFilterFromMap(object map[string]interface{}, eth chain.EthManager) *chain.Filter { + filter := chain.NewFilter(eth) if object["earliest"] != nil { val := ethutil.NewValue(object["earliest"]) @@ -46,7 +46,7 @@ func NewFilterFromMap(object map[string]interface{}, eth ethchain.EthManager) *e } // Conversion methodn -func mapToAccountChange(m map[string]interface{}) (d ethchain.AccountChange) { +func mapToAccountChange(m map[string]interface{}) (d chain.AccountChange) { if str, ok := m["id"].(string); ok { d.Address = ethutil.Hex2Bytes(str) } @@ -60,9 +60,9 @@ func mapToAccountChange(m map[string]interface{}) (d ethchain.AccountChange) { // data can come in in the following formats: // ["aabbccdd", {id: "ccddee", at: "11223344"}], "aabbcc", {id: "ccddee", at: "1122"} -func makeAltered(v interface{}) (d []ethchain.AccountChange) { +func makeAltered(v interface{}) (d []chain.AccountChange) { if str, ok := v.(string); ok { - d = append(d, ethchain.AccountChange{ethutil.Hex2Bytes(str), nil}) + d = append(d, chain.AccountChange{ethutil.Hex2Bytes(str), nil}) } else if obj, ok := v.(map[string]interface{}); ok { d = append(d, mapToAccountChange(obj)) } else if slice, ok := v.([]interface{}); ok { diff --git a/ui/qt/filter.go b/ui/qt/filter.go index 1fd99e78e..96c3ab3a3 100644 --- a/ui/qt/filter.go +++ b/ui/qt/filter.go @@ -3,12 +3,12 @@ package qt import ( "fmt" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ui" "gopkg.in/qml.v1" ) -func NewFilterFromMap(object map[string]interface{}, eth ethchain.EthManager) *ethchain.Filter { +func NewFilterFromMap(object map[string]interface{}, eth chain.EthManager) *chain.Filter { filter := ui.NewFilterFromMap(object, eth) if object["altered"] != nil { @@ -18,7 +18,7 @@ func NewFilterFromMap(object map[string]interface{}, eth ethchain.EthManager) *e return filter } -func makeAltered(v interface{}) (d []ethchain.AccountChange) { +func makeAltered(v interface{}) (d []chain.AccountChange) { if qList, ok := v.(*qml.List); ok { var s []interface{} qList.Convert(&s) diff --git a/utils/vm_env.go b/utils/vm_env.go index 9d9bbf4ec..0a7b589ee 100644 --- a/utils/vm_env.go +++ b/utils/vm_env.go @@ -3,20 +3,20 @@ package utils import ( "math/big" - "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/vm" ) type VMEnv struct { state *ethstate.State - block *ethchain.Block + block *chain.Block transactor []byte value *big.Int } -func NewEnv(state *ethstate.State, block *ethchain.Block, transactor []byte, value *big.Int) *VMEnv { +func NewEnv(state *ethstate.State, block *chain.Block, transactor []byte, value *big.Int) *VMEnv { return &VMEnv{ state: state, block: block, -- cgit v1.2.3