diff options
-rw-r--r-- | block_pool.go | 6 | ||||
-rw-r--r-- | cmd/ethereum/main.go | 2 | ||||
-rw-r--r-- | ethchain/block.go | 138 | ||||
-rw-r--r-- | ethchain/bloom9.go | 47 | ||||
-rw-r--r-- | ethchain/bloom9_test.go | 17 | ||||
-rw-r--r-- | ethchain/chain_manager.go | 2 | ||||
-rw-r--r-- | ethchain/derive_sha.go | 20 | ||||
-rw-r--r-- | ethchain/filter.go | 13 | ||||
-rw-r--r-- | ethchain/genesis.go | 11 | ||||
-rw-r--r-- | ethchain/helper_test.go | 6 | ||||
-rw-r--r-- | ethchain/state_manager.go | 35 | ||||
-rw-r--r-- | ethchain/state_transition.go | 12 | ||||
-rw-r--r-- | ethchain/transaction.go | 52 | ||||
-rw-r--r-- | ethcrypto/crypto_test.go | 33 | ||||
-rw-r--r-- | ethminer/miner.go | 33 | ||||
-rw-r--r-- | ethpipe/pipe_test.go | 58 | ||||
-rw-r--r-- | ethstate/state.go | 26 | ||||
-rw-r--r-- | ethtrie/trie.go | 40 | ||||
-rw-r--r-- | ethutil/rlp.go | 6 | ||||
-rw-r--r-- | ethutil/value.go | 4 | ||||
-rw-r--r-- | ethwire/client_identity_test.go | 12 | ||||
-rw-r--r-- | vm/common.go | 23 | ||||
-rw-r--r-- | vm/log.go | 33 | ||||
-rw-r--r-- | vm/vm_debug.go | 11 | ||||
-rw-r--r-- | vm/vm_test.go | 54 |
25 files changed, 405 insertions, 289 deletions
diff --git a/block_pool.go b/block_pool.go index f65d9d576..334db9c1b 100644 --- a/block_pool.go +++ b/block_pool.go @@ -309,9 +309,13 @@ out: } } + // TODO figure out whether we were catching up + // If caught up and just a new block has been propagated: + // sm.eth.EventMux().Post(NewBlockEvent{block}) + // otherwise process and don't emit anything var err error for i, block := range blocks { - err = self.eth.StateManager().Process(block, false) + err = self.eth.StateManager().Process(block) if err != nil { poollogger.Infoln(err) poollogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 9e9a3e356..b78d49cae 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -98,6 +98,8 @@ func main() { // Leave the Println. This needs clean output for piping fmt.Printf("%s\n", block.State().Dump()) + fmt.Println(block) + os.Exit(0) } diff --git a/ethchain/block.go b/ethchain/block.go index b98d806d8..b31d68e4d 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" "sort" - _ "strconv" "time" "github.com/ethereum/go-ethereum/ethcrypto" @@ -96,9 +95,10 @@ type Block struct { // Block Nonce for verification Nonce ethutil.Bytes // List of transactions and/or contracts - transactions []*Transaction - receipts []*Receipt - TxSha []byte + transactions Transactions + receipts Receipts + TxSha, ReceiptSha []byte + LogsBloom []byte } func NewBlockFromBytes(raw []byte) *Block { @@ -151,7 +151,7 @@ func (block *Block) Hash() ethutil.Bytes { func (block *Block) HashNoNonce() []byte { return ethcrypto.Sha3(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Trie.Root, - block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, + block.ReceiptSha, block.Difficulty, block.Number, block.MinGasPrice, block.GasLimit, block.GasUsed, block.Time, block.Extra})) } @@ -191,9 +191,9 @@ func (block *Block) BlockInfo() BlockInfo { } func (self *Block) GetTransaction(hash []byte) *Transaction { - for _, receipt := range self.receipts { - if bytes.Compare(receipt.Tx.Hash(), hash) == 0 { - return receipt.Tx + for _, tx := range self.transactions { + if bytes.Compare(tx.Hash(), hash) == 0 { + return tx } } @@ -236,45 +236,34 @@ func (block *Block) rlpUncles() interface{} { func (block *Block) SetUncles(uncles []*Block) { block.Uncles = uncles - // Sha of the concatenated uncles - if len(uncles) > 0 { - block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) - } + block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) } -func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { +func (self *Block) SetReceipts(receipts Receipts) { self.receipts = receipts + self.SetReceiptHash(receipts) +} + +func (self *Block) SetTransactions(txs Transactions) { self.setTransactions(txs) + self.SetTransactionHash(txs) } -func (block *Block) setTransactions(txs []*Transaction) { +func (block *Block) setTransactions(txs Transactions) { block.transactions = txs + block.LogsBloom = CreateBloom(block) } -func CreateTxSha(receipts Receipts) (sha []byte) { - trie := ethtrie.New(ethutil.Config.Db, "") - for i, receipt := range receipts { - trie.Update(string(ethutil.NewValue(i).Encode()), string(ethutil.NewValue(receipt.RlpData()).Encode())) - } - - switch trie.Root.(type) { - case string: - sha = []byte(trie.Root.(string)) - case []byte: - sha = trie.Root.([]byte) - default: - panic(fmt.Sprintf("invalid root type %T", trie.Root)) - } - - return sha +func (self *Block) SetTransactionHash(transactions Transactions) { + self.TxSha = DeriveSha(transactions) } -func (self *Block) SetTxHash(receipts Receipts) { - self.TxSha = CreateTxSha(receipts) +func (self *Block) SetReceiptHash(receipts Receipts) { + self.ReceiptSha = DeriveSha(receipts) } func (block *Block) Value() *ethutil.Value { - return ethutil.NewValue([]interface{}{block.header(), block.rlpReceipts(), block.rlpUncles()}) + return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()}) } func (block *Block) RlpEncode() []byte { @@ -289,33 +278,20 @@ func (block *Block) RlpDecode(data []byte) { } func (block *Block) RlpValueDecode(decoder *ethutil.Value) { - header := decoder.Get(0) - - block.PrevHash = header.Get(0).Bytes() - block.UncleSha = header.Get(1).Bytes() - block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) - block.TxSha = header.Get(4).Bytes() - block.Difficulty = header.Get(5).BigInt() - block.Number = header.Get(6).BigInt() - //fmt.Printf("#%v : %x\n", block.Number, block.Coinbase) - block.MinGasPrice = header.Get(7).BigInt() - block.GasLimit = header.Get(8).BigInt() - block.GasUsed = header.Get(9).BigInt() - block.Time = int64(header.Get(10).BigInt().Uint64()) - block.Extra = header.Get(11).Str() - block.Nonce = header.Get(12).Bytes() + 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.transactions = make([]*Transaction, receipts.Len()) - block.receipts = make([]*Receipt, receipts.Len()) - for i := 0; i < receipts.Len(); i++ { - receipt := NewRecieptFromValue(receipts.Get(i)) - block.transactions[i] = receipt.Tx - block.receipts[i] = receipt + //receipts := decoder.Get(1) + //block.receipts = make([]*Receipt, receipts.Len()) + it := decoder.Get(1).NewIterator() + block.transactions = make(Transactions, it.Len()) + for it.Next() { + block.transactions[it.Idx()] = NewTransactionFromValue(it.Value()) + //receipt := NewRecieptFromValue(receipts.Get(i)) + //block.transactions[i] = receipt.Tx + //block.receipts[i] = receipt } } @@ -330,22 +306,27 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { } +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.PrevHash = header.Get(0).Bytes() - block.UncleSha = header.Get(1).Bytes() - block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) - block.TxSha = header.Get(4).Bytes() - block.Difficulty = header.Get(5).BigInt() - block.Number = header.Get(6).BigInt() - block.MinGasPrice = header.Get(7).BigInt() - block.GasLimit = header.Get(8).BigInt() - block.GasUsed = header.Get(9).BigInt() - block.Time = int64(header.Get(10).BigInt().Uint64()) - block.Extra = header.Get(11).Str() - block.Nonce = header.Get(12).Bytes() + block.setHeader(header) return block } @@ -376,8 +357,12 @@ func (block *Block) header() []interface{} { block.Coinbase, // root state block.state.Trie.Root, - // Sha of tx + // tx root block.TxSha, + // Sha of tx + block.ReceiptSha, + // Bloom + block.LogsBloom, // Current block Difficulty block.Difficulty, // The block number @@ -404,7 +389,9 @@ func (block *Block) String() string { UncleSha: %x Coinbase: %x Root: %x - TxSha: %x + TxSha %x + ReceiptSha: %x + Bloom: %x Difficulty: %v Number: %v MinGas: %v @@ -422,6 +409,8 @@ func (block *Block) String() string { block.Coinbase, block.state.Trie.Root, block.TxSha, + block.ReceiptSha, + block.LogsBloom, block.Difficulty, block.Number, block.MinGasPrice, @@ -437,3 +426,8 @@ func (block *Block) String() string { 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/bloom9.go b/ethchain/bloom9.go index 65be6c7a2..4028231a3 100644 --- a/ethchain/bloom9.go +++ b/ethchain/bloom9.go @@ -1,38 +1,55 @@ package ethchain -import "github.com/ethereum/go-ethereum/vm" - -func CreateBloom(txs Transactions) uint64 { - var bin uint64 - for _, tx := range txs { - bin |= logsBloom(tx.logs) +import ( + "math/big" + + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/vm" +) + +func CreateBloom(block *Block) []byte { + bin := new(big.Int) + bin.Or(bin, bloom9(block.Coinbase)) + for _, tx := range block.Transactions() { + bin.Or(bin, LogsBloom(tx.logs)) } - return bin + return bin.Bytes() } -func logsBloom(logs []vm.Log) uint64 { - var bin uint64 +func LogsBloom(logs []vm.Log) *big.Int { + bin := new(big.Int) for _, log := range logs { data := [][]byte{log.Address} for _, topic := range log.Topics { - data = append(data, topic.Bytes()) + data = append(data, topic) + } + + if log.Data != nil { + data = append(data, log.Data) } - data = append(data, log.Data) for _, b := range data { - bin |= bloom9(b) + bin.Or(bin, bloom9(b)) } } return bin } -func bloom9(b []byte) uint64 { - var r uint64 +func bloom9(b []byte) *big.Int { + r := new(big.Int) for _, i := range []int{0, 2, 4} { - r |= 1 << (uint64(b[i+1]) + 256*(uint64(b[i])&1)) + 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 new file mode 100644 index 000000000..40f30f35d --- /dev/null +++ b/ethchain/bloom9_test.go @@ -0,0 +1,17 @@ +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/chain_manager.go b/ethchain/chain_manager.go index d949f0ce7..46990bb22 100644 --- a/ethchain/chain_manager.go +++ b/ethchain/chain_manager.go @@ -87,8 +87,6 @@ func (bc *ChainManager) Reset() { bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) - fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) - bc.Ethereum.Db().Put(fk, make([]byte, 255)) bc.CurrentBlock = bc.genesisBlock bc.SetTotalDifficulty(ethutil.Big("0")) diff --git a/ethchain/derive_sha.go b/ethchain/derive_sha.go new file mode 100644 index 000000000..b41252e39 --- /dev/null +++ b/ethchain/derive_sha.go @@ -0,0 +1,20 @@ +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/filter.go b/ethchain/filter.go index 4e7fe68a8..b0edea7a0 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -2,7 +2,6 @@ package ethchain import ( "bytes" - "fmt" "math" "github.com/ethereum/go-ethereum/ethstate" @@ -171,18 +170,10 @@ func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message } func (self *Filter) bloomFilter(block *Block) bool { - fk := append([]byte("bloom"), block.Hash()...) - bin, err := self.eth.Db().Get(fk) - if err != nil { - fmt.Println(err) - } - - bloom := NewBloomFilter(bin) - var fromIncluded, toIncluded bool if len(self.from) > 0 { for _, from := range self.from { - if bloom.Search(from) { + if BloomLookup(block.LogsBloom, from) { fromIncluded = true break } @@ -193,7 +184,7 @@ func (self *Filter) bloomFilter(block *Block) bool { if len(self.to) > 0 { for _, to := range self.to { - if bloom.Search(to) { + if BloomLookup(block.LogsBloom, to) { toIncluded = true break } diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 232986d53..d94e658b6 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -13,19 +13,24 @@ import ( 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), diff --git a/ethchain/helper_test.go b/ethchain/helper_test.go index e4aef67d0..a863c7541 100644 --- a/ethchain/helper_test.go +++ b/ethchain/helper_test.go @@ -18,7 +18,7 @@ type TestManager struct { db ethutil.Database txPool *TxPool - blockChain *BlockChain + blockChain *ChainManager Blocks []*Block } @@ -38,7 +38,7 @@ func (s *TestManager) Peers() *list.List { return list.New() } -func (s *TestManager) BlockChain() *BlockChain { +func (s *TestManager) ChainManager() *ChainManager { return s.blockChain } @@ -82,7 +82,7 @@ func NewTestManager() *TestManager { testManager.eventMux = new(event.TypeMux) testManager.db = db testManager.txPool = NewTxPool(testManager) - testManager.blockChain = NewBlockChain(testManager) + testManager.blockChain = NewChainManager(testManager) testManager.stateManager = NewStateManager(testManager) // Start the tx pool diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index dba3ff202..e45d44752 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -101,7 +101,7 @@ func (self *StateManager) Stop() { func (self *StateManager) updateThread() { for ev := range self.events.Chan() { for _, block := range ev.(Blocks) { - err := self.Process(block, false) + err := self.Process(block) if err != nil { statelogger.Infoln(err) statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) @@ -173,8 +173,9 @@ done: state.Update() txGas.Sub(txGas, st.gas) - accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) - receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + 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(tx.logs).Bytes(), tx.logs} if i < len(block.Receipts()) { original := block.Receipts()[i] @@ -183,7 +184,7 @@ done: 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], receipt.Tx.Hash()[0:4]) + 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 } @@ -205,7 +206,7 @@ done: return receipts, handled, unhandled, erroneous, err } -func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { +func (sm *StateManager) Process(block *Block) (err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -235,14 +236,19 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { 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.ReceiptSha, txSha) + } + receipts, err := sm.ApplyDiff(state, parent, block) if err != nil { return err } - txSha := CreateTxSha(receipts) - if bytes.Compare(txSha, block.TxSha) != 0 { - return fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha) + 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 @@ -271,20 +277,13 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Add the block to the chain sm.bc.Add(block) - sm.transState = state.Copy() + // TODO at this point we should also insert LOGS in to a database - // Create a bloom bin for this block - filter := sm.createBloomFilter(state) - // Persist the data - fk := append([]byte("bloom"), block.Hash()...) - sm.eth.Db().Put(fk, filter.Bin()) + sm.transState = state.Copy() statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) - if dontReact == false { - sm.eth.EventMux().Post(NewBlockEvent{block}) - state.Manifest().Reset() - } + state.Manifest().Reset() sm.eth.TxPool().RemoveSet(block.Transactions()) } else { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index e6863b61f..809e5ad6a 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethtrie" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/vm" ) @@ -231,11 +230,9 @@ func (self *StateTransition) TransitionState() (err error) { msg.Output = ret } else { - // Add default LOG - // PUSH1 1 CALLER ADD LOG1 - addr := ethutil.BigD(sender.Address()) - addr.Add(addr, ethutil.Big1) - tx.addLog(vm.Log{sender.Address(), []*big.Int{addr}, nil}) + // Add default LOG. Default = big(sender.addr) + 1 + addr := ethutil.BigD(receiver.Address()) + tx.addLog(vm.Log{sender.Address(), [][]byte{addr.Add(addr, ethutil.Big1).Bytes()}, nil}) } } @@ -250,9 +247,7 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context callerClosure = vm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) ) - //vm := vm.New(env, vm.Type(ethutil.Config.VmType)) evm := vm.New(env, vm.DebugVmTy) - ret, _, err = callerClosure.Call(evm, self.tx.Data) return @@ -264,7 +259,6 @@ func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject contract := state.GetOrNewStateObject(addr) contract.InitCode = tx.Data - contract.State = ethstate.New(ethtrie.New(ethutil.Config.Db, "")) return contract } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index abf2e37ac..10bf5bc8e 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -113,7 +113,8 @@ func (tx *Transaction) PublicKey() []byte { sig := append(r, s...) sig = append(sig, tx.v-27) - pubkey, _ := secp256k1.RecoverPubkey(hash, sig) + pubkey := ethcrypto.Ecrecover(append(hash, sig...)) + //pubkey, _ := secp256k1.RecoverPubkey(hash, sig) return pubkey } @@ -208,11 +209,11 @@ func (tx *Transaction) String() string { } type Receipt struct { - Tx *Transaction PostState []byte CumulativeGasUsed *big.Int + Bloom []byte + Logs vm.Logs } -type Receipts []*Receipt func NewRecieptFromValue(val *ethutil.Value) *Receipt { r := &Receipt{} @@ -222,25 +223,22 @@ func NewRecieptFromValue(val *ethutil.Value) *Receipt { } func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { - self.Tx = NewTransactionFromValue(decoder.Get(0)) - self.PostState = decoder.Get(1).Bytes() - self.CumulativeGasUsed = decoder.Get(2).BigInt() + 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, vm.NewLogFromValue(it.Value())) + } } func (self *Receipt) RlpData() interface{} { - return []interface{}{self.Tx.RlpData(), self.PostState, self.CumulativeGasUsed} + return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.Logs.RlpData()} } -func (self *Receipt) String() string { - return fmt.Sprintf(` - R - Tx:[ %v] - PostState: 0x%x - CumulativeGasUsed: %v - `, - self.Tx, - self.PostState, - self.CumulativeGasUsed) +func (self *Receipt) RlpEncode() []byte { + return ethutil.Encode(self.RlpData()) } func (self *Receipt) Cmp(other *Receipt) bool { @@ -251,11 +249,27 @@ func (self *Receipt) Cmp(other *Receipt) bool { 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 (s Transactions) Len() int { return len(s) } -func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +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 } diff --git a/ethcrypto/crypto_test.go b/ethcrypto/crypto_test.go index 689bcecb4..e8db6362f 100644 --- a/ethcrypto/crypto_test.go +++ b/ethcrypto/crypto_test.go @@ -2,16 +2,35 @@ package ethcrypto import ( "bytes" + "encoding/hex" "testing" - - "github.com/ethereum/go-ethereum/ethutil" ) -// FIPS 202 test (reverted back to FIPS 180) +// These tests are sanity checks. +// They should ensure that we don't e.g. use Sha3-224 instead of Sha3-256 +// and that the sha3 library uses keccak-f permutation. + func TestSha3(t *testing.T) { - const exp = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" - sha3_256 := Sha3Bin([]byte("abc")) - if bytes.Compare(sha3_256, ethutil.Hex2Bytes(exp)) != 0 { - t.Errorf("Sha3_256 failed. Incorrect result %x", sha3_256) + msg := []byte("abc") + exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") + checkhash(t, "Sha3-256", Sha3, msg, exp) +} + +func TestSha256(t *testing.T) { + msg := []byte("abc") + exp, _ := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + checkhash(t, "Sha256", Sha256, msg, exp) +} + +func TestRipemd160(t *testing.T) { + msg := []byte("abc") + exp, _ := hex.DecodeString("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc") + checkhash(t, "Ripemd160", Ripemd160, msg, exp) +} + +func checkhash(t *testing.T, name string, f func([]byte) []byte, msg, exp []byte) { + sum := f(msg) + if bytes.Compare(exp, sum) != 0 { + t.Errorf("hash %s returned wrong result.\ngot: %x\nwant: %x", name, sum, exp) } } diff --git a/ethminer/miner.go b/ethminer/miner.go index e0bef078b..24af7fbcb 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -85,11 +85,7 @@ func (miner *Miner) listener() { for { select { - case event, isopen := <-miner.events.Chan(): - if !isopen { - return - } - + case event := <-miner.events.Chan(): switch event := event.(type) { case ethchain.NewBlockEvent: miner.stopMining() @@ -114,16 +110,13 @@ func (miner *Miner) listener() { } } miner.txs = newtxs - - // Setup a fresh state to mine on - //miner.block = miner.ethereum.ChainManager().NewBlock(miner.coinbase, miner.txs) - } else { if bytes.Compare(block.PrevHash, miner.ethereum.ChainManager().CurrentBlock.PrevHash) == 0 { logger.Infoln("Adding uncle block") miner.uncles = append(miner.uncles, block) } } + miner.startMining() case ethchain.TxEvent: if event.Type == ethchain.TxPre { @@ -141,6 +134,8 @@ func (miner *Miner) listener() { // Apply new transactions miner.txs = append(miner.txs, event.Tx) } + + miner.startMining() } } @@ -159,8 +154,12 @@ func (miner *Miner) startMining() { } func (miner *Miner) stopMining() { - close(miner.powQuitChan) - <-miner.powDone + println("stop mining") + _, isopen := <-miner.powQuitChan + if isopen { + close(miner.powQuitChan) + } + //<-miner.powDone } func (self *Miner) mineNewBlock() { @@ -187,10 +186,9 @@ func (self *Miner) mineNewBlock() { } self.ethereum.TxPool().RemoveSet(erroneous) self.txs = append(txs, unhandledTxs...) - self.block.SetTxHash(receipts) - // Set the transactions to the block so the new SHA3 can be calculated - self.block.SetReceipts(receipts, txs) + self.block.SetReceipts(receipts) + self.block.SetTransactions(txs) // Accumulate the rewards included for this block stateManager.AccumelateRewards(self.block.State(), self.block, parent) @@ -203,7 +201,7 @@ func (self *Miner) mineNewBlock() { nonce := self.pow.Search(self.block, self.powQuitChan) if nonce != nil { self.block.Nonce = nonce - err := self.ethereum.StateManager().Process(self.block, false) + err := self.ethereum.StateManager().Process(self.block) if err != nil { logger.Infoln(err) } else { @@ -212,7 +210,10 @@ 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}) } + + // Continue mining on the next block + self.startMining() } - self.powDone <- struct{}{} } diff --git a/ethpipe/pipe_test.go b/ethpipe/pipe_test.go deleted file mode 100644 index 3b5dc5e4c..000000000 --- a/ethpipe/pipe_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package ethpipe - -import ( - "testing" - - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethutil" -) - -func Val(v interface{}) *ethutil.Value { - return ethutil.NewValue(v) -} - -func TestNew(t *testing.T) { - pipe := New(nil) - - var addr, privy, recp, data []byte - var object *ethstate.StateObject - var key *ethcrypto.KeyPair - - world := pipe.World() - world.Get(addr) - world.Coinbase() - world.IsMining() - world.IsListening() - world.State() - peers := world.Peers() - peers.Len() - - // Shortcut functions - pipe.Balance(addr) - pipe.Nonce(addr) - pipe.Block(addr) - pipe.Storage(addr, addr) - pipe.ToAddress(privy) - pipe.Exists(addr) - // Doesn't change state - pipe.Execute(addr, nil, Val(0), Val(1000000), Val(10)) - // Doesn't change state - pipe.ExecuteObject(object, nil, Val(0), Val(1000000), Val(10)) - - conf := world.Config() - namereg := conf.Get("NameReg") - namereg.Storage(addr) - - var err error - // Transact - err = pipe.Transact(key, recp, ethutil.NewValue(0), ethutil.NewValue(0), ethutil.NewValue(0), nil) - if err != nil { - t.Error(err) - } - // Create - err = pipe.Transact(key, nil, ethutil.NewValue(0), ethutil.NewValue(0), ethutil.NewValue(0), data) - if err != nil { - t.Error(err) - } -} diff --git a/ethstate/state.go b/ethstate/state.go index c23dab330..97958cc0a 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -22,11 +22,13 @@ type State struct { stateObjects map[string]*StateObject manifest *Manifest + + refund map[string]*big.Int } // Create a new state from a given trie func New(trie *ethtrie.Trie) *State { - return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} + return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest(), refund: make(map[string]*big.Int)} } // Retrieve the balance from the given address or 0 if object not found @@ -39,6 +41,16 @@ func (self *State) GetBalance(addr []byte) *big.Int { return ethutil.Big0 } +func (self *State) Refund(addr []byte, gas, price *big.Int) { + amount := new(big.Int).Mul(gas, price) + + if self.refund[string(addr)] == nil { + self.refund[string(addr)] = new(big.Int) + } + + self.refund[string(addr)] = new(big.Int).Add(self.refund[string(addr)], amount) +} + func (self *State) AddBalance(addr []byte, amount *big.Int) { stateObject := self.GetStateObject(addr) if stateObject != nil { @@ -186,6 +198,10 @@ func (self *State) Copy() *State { state.stateObjects[k] = stateObject.Copy() } + for addr, refund := range self.refund { + state.refund[addr] = refund + } + return state } @@ -199,6 +215,7 @@ func (self *State) Set(state *State) { self.Trie = state.Trie self.stateObjects = state.stateObjects + self.refund = state.refund } func (s *State) Root() interface{} { @@ -240,10 +257,17 @@ func (s *State) Sync() { func (self *State) Empty() { self.stateObjects = make(map[string]*StateObject) + self.refund = make(map[string]*big.Int) } func (self *State) Update() { var deleted bool + + // Refund any gas that's left + for addr, amount := range self.refund { + self.GetStateObject([]byte(addr)).AddBalance(amount) + } + for _, stateObject := range self.stateObjects { if stateObject.remove { self.DeleteStateObject(stateObject) diff --git a/ethtrie/trie.go b/ethtrie/trie.go index 686971985..6db25db05 100644 --- a/ethtrie/trie.go +++ b/ethtrie/trie.go @@ -168,7 +168,24 @@ func New(db ethutil.Database, Root interface{}) *Trie { r := copyRoot(Root) p := copyRoot(Root) - return &Trie{cache: NewCache(db), Root: r, prevRoot: p} + trie := &Trie{cache: NewCache(db), Root: r, prevRoot: p} + trie.setRoot(Root) + + return trie +} + +func (self *Trie) setRoot(root interface{}) { + switch t := root.(type) { + case string: + if t == "" { + root = ethcrypto.Sha3([]byte("")) + } + self.Root = root + case []byte: + self.Root = root + default: + self.Root = self.cache.PutValue(root, true) + } } /* @@ -182,14 +199,7 @@ func (t *Trie) Update(key, value string) { k := CompactHexDecode(key) root := t.UpdateState(t.Root, k, value) - switch root.(type) { - case string: - t.Root = root - case []byte: - t.Root = root - default: - t.Root = t.cache.PutValue(root, true) - } + t.setRoot(root) } func (t *Trie) Get(key string) string { @@ -209,13 +219,17 @@ func (t *Trie) Delete(key string) { k := CompactHexDecode(key) root := t.deleteState(t.Root, k) - switch root.(type) { + t.setRoot(root) +} + +func (self *Trie) GetRoot() []byte { + switch self.Root.(type) { case string: - t.Root = root + return []byte(self.Root.(string)) case []byte: - t.Root = root + return self.Root.([]byte) default: - t.Root = t.cache.PutValue(root, true) + panic(fmt.Sprintf("invalid root type %T", self.Root)) } } diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 55406133b..1fff2b28a 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -15,6 +15,10 @@ type RlpEncodeDecode interface { RlpValue() []interface{} } +type RlpEncodable interface { + RlpData() interface{} +} + func Rlp(encoder RlpEncode) []byte { return encoder.RlpEncode() } @@ -100,6 +104,8 @@ func Encode(object interface{}) []byte { switch t := object.(type) { case *Value: buff.Write(Encode(t.Raw())) + case RlpEncodable: + buff.Write(Encode(t.RlpData())) // Code dup :-/ case int: buff.Write(Encode(big.NewInt(int64(t)))) diff --git a/ethutil/value.go b/ethutil/value.go index dd777fa43..6417b0008 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -377,6 +377,10 @@ func (val *Value) NewIterator() *ValueIterator { return &ValueIterator{value: val} } +func (it *ValueIterator) Len() int { + return it.value.Len() +} + func (it *ValueIterator) Next() bool { if it.idx >= it.value.Len() { return false diff --git a/ethwire/client_identity_test.go b/ethwire/client_identity_test.go index f3c8bfd50..1724fe57b 100644 --- a/ethwire/client_identity_test.go +++ b/ethwire/client_identity_test.go @@ -9,22 +9,22 @@ import ( func TestClientIdentity(t *testing.T) { clientIdentity := NewSimpleClientIdentity("Ethereum(G)", "0.5.16", "test") clientString := clientIdentity.String() - expected := fmt.Sprintf("Ethereum(G)/v0.5.16/test/%s/Go", runtime.GOOS) + expected := fmt.Sprintf("Ethereum(G)/v0.5.16/test/%s/%s", runtime.GOOS, runtime.Version()) if clientString != expected { - t.Error("Expected clientIdentity to be %v, got %v", expected, clientString) + t.Errorf("Expected clientIdentity to be %q, got %q", expected, clientString) } customIdentifier := clientIdentity.GetCustomIdentifier() if customIdentifier != "test" { - t.Error("Expected clientIdentity.GetCustomIdentifier() to be 'test', got %v", customIdentifier) + t.Errorf("Expected clientIdentity.GetCustomIdentifier() to be 'test', got %q", customIdentifier) } clientIdentity.SetCustomIdentifier("test2") customIdentifier = clientIdentity.GetCustomIdentifier() if customIdentifier != "test2" { - t.Error("Expected clientIdentity.GetCustomIdentifier() to be 'test2', got %v", customIdentifier) + t.Errorf("Expected clientIdentity.GetCustomIdentifier() to be 'test2', got %q", customIdentifier) } clientString = clientIdentity.String() - expected = fmt.Sprintf("Ethereum(G)/v0.5.16/test2/%s/Go", runtime.GOOS) + expected = fmt.Sprintf("Ethereum(G)/v0.5.16/test2/%s/%s", runtime.GOOS, runtime.Version()) if clientString != expected { - t.Error("Expected clientIdentity to be %v, got %v", expected, clientString) + t.Errorf("Expected clientIdentity to be %q, got %q", expected, clientString) } } diff --git a/vm/common.go b/vm/common.go index c73744506..16a0b5523 100644 --- a/vm/common.go +++ b/vm/common.go @@ -19,17 +19,18 @@ const ( ) var ( - GasStep = big.NewInt(1) - GasSha = big.NewInt(20) - GasSLoad = big.NewInt(20) - GasSStore = big.NewInt(100) - GasBalance = big.NewInt(20) - GasCreate = big.NewInt(100) - GasCall = big.NewInt(20) - GasMemory = big.NewInt(1) - GasData = big.NewInt(5) - GasTx = big.NewInt(500) - GasLog = big.NewInt(32) + GasStep = big.NewInt(1) + GasSha = big.NewInt(20) + GasSLoad = big.NewInt(20) + GasSStore = big.NewInt(100) + GasSStoreRefund = big.NewInt(100) + GasBalance = big.NewInt(20) + GasCreate = big.NewInt(100) + GasCall = big.NewInt(20) + GasMemory = big.NewInt(1) + GasData = big.NewInt(5) + GasTx = big.NewInt(500) + GasLog = big.NewInt(32) Pow256 = ethutil.BigPow(2, 256) @@ -1,9 +1,38 @@ package vm -import "math/big" +import "github.com/ethereum/go-ethereum/ethutil" type Log struct { Address []byte - Topics []*big.Int + Topics [][]byte Data []byte } + +func NewLogFromValue(decoder *ethutil.Value) Log { + log := Log{ + Address: decoder.Get(0).Bytes(), + Data: decoder.Get(2).Bytes(), + } + + it := decoder.Get(1).NewIterator() + for it.Next() { + log.Topics = append(log.Topics, it.Value().Bytes()) + } + + return log +} + +func (self Log) RlpData() interface{} { + return []interface{}{self.Address, ethutil.ByteSliceToInterface(self.Topics), self.Data} +} + +type Logs []Log + +func (self Logs) RlpData() interface{} { + data := make([]interface{}, len(self)) + for i, log := range self { + data[i] = log.RlpData() + } + + return data +} diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 13446d6c0..b3fbfe341 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -169,9 +169,13 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(ethutil.Big0) case SLOAD: + require(1) + gas.Set(GasSLoad) // Memory resize & Gas case SSTORE: + require(2) + var mult *big.Int y, x := stack.Peekn() val := closure.GetStorage(x) @@ -179,7 +183,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0 => non 0 mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - //state.AddBalance(closure.caller.Address(), new(big.Int).Mul(big.NewInt(100), closure.Price)) + state.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) + mult = ethutil.Big0 } else { // non 0 => non 0 @@ -699,11 +704,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) - topics := make([]*big.Int, n) + topics := make([][]byte, n) mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64() data := mem.Geti(mStart, mSize) for i := 0; i < n; i++ { - topics[i] = stack.Pop() + topics[i] = stack.Pop().Bytes() } self.env.AddLog(Log{closure.Address(), topics, data}) case MLOAD: diff --git a/vm/vm_test.go b/vm/vm_test.go index 84cca3a9d..8818cc8ec 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -14,22 +14,30 @@ import ( "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethtrie" "github.com/ethereum/go-ethereum/ethutil" + "github.com/obscuren/mutan" ) -type TestEnv struct { +type TestEnv struct{} + +func (TestEnv) Origin() []byte { return nil } +func (TestEnv) BlockNumber() *big.Int { return nil } +func (TestEnv) BlockHash() []byte { return nil } +func (TestEnv) PrevHash() []byte { return nil } +func (TestEnv) Coinbase() []byte { return nil } +func (TestEnv) Time() int64 { return 0 } +func (TestEnv) GasLimit() *big.Int { return nil } +func (TestEnv) Difficulty() *big.Int { return nil } +func (TestEnv) Value() *big.Int { return nil } +func (TestEnv) AddLog(Log) {} + +func (TestEnv) Transfer(from, to Account, amount *big.Int) error { + return nil } -func (self TestEnv) Origin() []byte { return nil } -func (self TestEnv) BlockNumber() *big.Int { return nil } -func (self TestEnv) BlockHash() []byte { return nil } -func (self TestEnv) PrevHash() []byte { return nil } -func (self TestEnv) Coinbase() []byte { return nil } -func (self TestEnv) Time() int64 { return 0 } -func (self TestEnv) Difficulty() *big.Int { return nil } -func (self TestEnv) Value() *big.Int { return nil } - // This is likely to fail if anything ever gets looked up in the state trie :-) -func (self TestEnv) State() *ethstate.State { return ethstate.New(ethtrie.New(nil, "")) } +func (TestEnv) State() *ethstate.State { + return ethstate.New(ethtrie.New(nil, "")) +} const mutcode = ` var x = 0; @@ -56,27 +64,35 @@ func setup(level ethlog.LogLevel, typ Type) (*Closure, VirtualMachine) { return callerClosure, New(TestEnv{}, typ) } +var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") + func TestDebugVm(t *testing.T) { + if mutan.Version < "0.6" { + t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + } + closure, vm := setup(ethlog.DebugLevel, DebugVmTy) ret, _, e := closure.Call(vm, nil) if e != nil { - fmt.Println("error", e) + t.Fatalf("Call returned error: %v", e) } - - if ret[len(ret)-1] != 9 { - t.Errorf("Expected VM to return 9, got", ret, "instead.") + if !bytes.Equal(ret, big9) { + t.Errorf("Wrong return value '%x', want '%x'", ret, big9) } } func TestVm(t *testing.T) { + if mutan.Version < "0.6" { + t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + } + closure, vm := setup(ethlog.DebugLevel, StandardVmTy) ret, _, e := closure.Call(vm, nil) if e != nil { - fmt.Println("error", e) + t.Fatalf("Call returned error: %v", e) } - - if ret[len(ret)-1] != 9 { - t.Errorf("Expected VM to return 9, got", ret, "instead.") + if !bytes.Equal(ret, big9) { + t.Errorf("Wrong return value '%x', want '%x'", ret, big9) } } |