diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/block_processor.go | 68 | ||||
-rw-r--r-- | core/chain_makers.go | 142 | ||||
-rw-r--r-- | core/chain_manager.go | 41 | ||||
-rw-r--r-- | core/chain_manager_test.go | 194 | ||||
-rw-r--r-- | core/error.go | 18 | ||||
-rw-r--r-- | core/execution.go | 2 | ||||
-rw-r--r-- | core/filter.go | 2 | ||||
-rw-r--r-- | core/genesis.go | 17 | ||||
-rw-r--r-- | core/state_transition.go | 19 | ||||
-rw-r--r-- | core/transaction_pool.go | 9 | ||||
-rw-r--r-- | core/types/block.go | 58 | ||||
-rw-r--r-- | core/types/bloom9.go | 7 |
12 files changed, 511 insertions, 66 deletions
diff --git a/core/block_processor.go b/core/block_processor.go index 7eaeb5be0..34c12729c 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -12,7 +12,6 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" - "github.com/ethereum/go-ethereum/pow/ezp" "github.com/ethereum/go-ethereum/state" "gopkg.in/fatih/set.v0" ) @@ -46,11 +45,11 @@ type BlockProcessor struct { eventMux *event.TypeMux } -func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor { +func NewBlockProcessor(db ethutil.Database, pow pow.PoW, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor { sm := &BlockProcessor{ db: db, mem: make(map[string]*big.Int), - Pow: ezp.New(), + Pow: pow, bc: chainManager, eventMux: eventMux, txpool: txpool, @@ -105,6 +104,9 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated return receipt, txGas, err } +func (self *BlockProcessor) ChainManager() *ChainManager { + return self.bc +} func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) { var ( @@ -174,10 +176,15 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big state := state.New(parent.Root(), sm.db) // Block validation - if err = sm.ValidateBlock(block, parent); err != nil { + if err = sm.ValidateHeader(block.Header(), parent.Header()); err != nil { return } + // There can be at most two uncles + if len(block.Uncles()) > 2 { + return nil, ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles())) + } + receipts, err := sm.TransitionState(state, parent, block, false) if err != nil { return @@ -204,7 +211,6 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) receiptSha := types.DeriveSha(receipts) if bytes.Compare(receiptSha, header.ReceiptHash) != 0 { - fmt.Println("receipts", receipts) err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha) return } @@ -237,36 +243,38 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // 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 *BlockProcessor) ValidateBlock(block, parent *types.Block) error { - if len(block.Header().Extra) > 1024 { - return fmt.Errorf("Block extra data too long (%d)", len(block.Header().Extra)) +func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error { + if len(block.Extra) > 1024 { + return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) } expd := CalcDifficulty(block, parent) - if expd.Cmp(block.Header().Difficulty) != 0 { - return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd) + if expd.Cmp(block.Difficulty) != 0 { + return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) } - expl := CalcGasLimit(parent, block) - if expl.Cmp(block.Header().GasLimit) != 0 { - return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl) + // block.gasLimit - parent.gasLimit <= parent.gasLimit / 1024 + a := new(big.Int).Sub(block.GasLimit, parent.GasLimit) + b := new(big.Int).Div(parent.GasLimit, big.NewInt(1024)) + if a.Cmp(b) > 0 { + return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b) } - if block.Time() < parent.Time() { - return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time) + if block.Time <= parent.Time { + return ValidationError("Block timestamp not after or equal to prev block (%v - %v)", block.Time, parent.Time) } - if block.Time() > time.Now().Unix() { + if int64(block.Time) > time.Now().Unix() { return BlockFutureErr } - if new(big.Int).Sub(block.Number(), parent.Number()).Cmp(big.NewInt(1)) != 0 { + if new(big.Int).Sub(block.Number, parent.Number).Cmp(big.NewInt(1)) != 0 { return BlockNumberErr } // Verify the nonce of the block. Return an error if it's not valid - if !sm.Pow.Verify(block) { - return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce)) + if !sm.Pow.Verify(types.NewBlockWithHeader(block)) { + return ValidationError("Block's nonce is invalid (= %x)", block.Nonce) } return nil @@ -276,25 +284,41 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren reward := new(big.Int).Set(BlockReward) ancestors := set.New() + uncles := set.New() + ancestorHeaders := make(map[string]*types.Header) for _, ancestor := range sm.bc.GetAncestors(block, 7) { - ancestors.Add(string(ancestor.Hash())) + hash := string(ancestor.Hash()) + ancestorHeaders[hash] = ancestor.Header() + ancestors.Add(hash) + // Include ancestors uncles in the uncle set. Uncles must be unique. + for _, uncle := range ancestor.Uncles() { + uncles.Add(string(uncle.Hash())) + } } - uncles := set.New() uncles.Add(string(block.Hash())) for _, uncle := range block.Uncles() { if uncles.Has(string(uncle.Hash())) { // Error not unique return UncleError("Uncle not unique") } + uncles.Add(string(uncle.Hash())) + if ancestors.Has(string(uncle.Hash())) { + return UncleError("Uncle is ancestor") + } + if !ancestors.Has(string(uncle.ParentHash)) { return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } + if err := sm.ValidateHeader(uncle, ancestorHeaders[string(uncle.ParentHash)]); err != nil { + return ValidationError(fmt.Sprintf("%v", err)) + } + if !sm.Pow.Verify(types.NewBlockWithHeader(uncle)) { - return ValidationError("Uncle's nonce is invalid (= %v)", ethutil.Bytes2Hex(uncle.Nonce)) + return ValidationError("Uncle's nonce is invalid (= %x)", uncle.Nonce) } r := new(big.Int) diff --git a/core/chain_makers.go b/core/chain_makers.go new file mode 100644 index 000000000..fad9ac97b --- /dev/null +++ b/core/chain_makers.go @@ -0,0 +1,142 @@ +package core + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/pow" + "github.com/ethereum/go-ethereum/state" +) + +// So we can generate blocks easily +type FakePow struct{} + +func (f FakePow) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte, []byte) { + return 0, nil, nil +} +func (f FakePow) Verify(block pow.Block) bool { return true } +func (f FakePow) GetHashrate() int64 { return 0 } +func (f FakePow) Turbo(bool) {} + +// So we can deterministically seed different blockchains +var ( + CanonicalSeed = 1 + ForkSeed = 2 +) + +// Utility functions for making chains on the fly +// Exposed for sake of testing from other packages (eg. go-ethash) +func NewBlockFromParent(addr []byte, parent *types.Block) *types.Block { + return newBlockFromParent(addr, parent) +} + +func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database, seed int) *types.Block { + return makeBlock(bman, parent, i, db, seed) +} + +func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database, seed int) types.Blocks { + return makeChain(bman, parent, max, db, seed) +} + +func NewChainMan(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager { + return newChainManager(block, eventMux, db) +} + +func NewBlockProc(db ethutil.Database, txpool *TxPool, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor { + return newBlockProcessor(db, txpool, cman, eventMux) +} + +func NewCanonical(n int, db ethutil.Database) (*BlockProcessor, error) { + return newCanonical(n, db) +} + +// block time is fixed at 10 seconds +func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { + block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), 0, "") + block.SetUncles(nil) + block.SetTransactions(nil) + block.SetReceipts(nil) + + header := block.Header() + header.Difficulty = CalcDifficulty(block.Header(), parent.Header()) + header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) + header.Time = parent.Header().Time + 10 + header.GasLimit = CalcGasLimit(parent, block) + + block.Td = parent.Td + + return block +} + +// Actually make a block by simulating what miner would do +// we seed chains by the first byte of the coinbase +func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database, seed int) *types.Block { + addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) + addr[0] = byte(seed) + block := newBlockFromParent(addr, parent) + state := state.New(block.Root(), db) + cbase := state.GetOrNewStateObject(addr) + cbase.SetGasPool(CalcGasLimit(parent, block)) + cbase.AddBalance(BlockReward) + state.Update(ethutil.Big0) + block.SetRoot(state.Root()) + return block +} + +// Make a chain with real blocks +// Runs ProcessWithParent to get proper state roots +func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database, seed int) types.Blocks { + bman.bc.currentBlock = parent + blocks := make(types.Blocks, max) + for i := 0; i < max; i++ { + block := makeBlock(bman, parent, i, db, seed) + td, err := bman.processWithParent(block, parent) + if err != nil { + fmt.Println("process with parent failed", err) + panic(err) + } + block.Td = td + blocks[i] = block + parent = block + } + return blocks +} + +// Create a new chain manager starting from given block +// Effectively a fork factory +func newChainManager(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager { + bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: eventMux} + if block == nil { + bc.Reset() + } else { + bc.currentBlock = block + bc.td = block.Td + } + return bc +} + +// block processor with fake pow +func newBlockProcessor(db ethutil.Database, txpool *TxPool, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor { + bman := NewBlockProcessor(db, FakePow{}, txpool, newChainManager(nil, eventMux, db), eventMux) + return bman +} + +// Make a new, deterministic canonical chain by running InsertChain +// on result of makeChain +func newCanonical(n int, db ethutil.Database) (*BlockProcessor, error) { + eventMux := &event.TypeMux{} + txpool := NewTxPool(eventMux) + + bman := newBlockProcessor(db, txpool, newChainManager(nil, eventMux, db), eventMux) + bman.bc.SetProcessor(bman) + parent := bman.bc.CurrentBlock() + if n == 0 { + return bman, nil + } + lchain := makeChain(bman, parent, n, db, CanonicalSeed) + err := bman.bc.InsertChain(lchain) + return bman, err +} diff --git a/core/chain_manager.go b/core/chain_manager.go index 959bfd398..d2a6560c1 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -14,7 +14,10 @@ import ( "github.com/ethereum/go-ethereum/state" ) -var chainlogger = logger.NewLogger("CHAIN") +var ( + chainlogger = logger.NewLogger("CHAIN") + jsonlogger = logger.NewJsonLogger() +) type ChainEvent struct { Block *types.Block @@ -25,14 +28,19 @@ type StateQuery interface { GetAccount(addr []byte) *state.StateObject } -func CalcDifficulty(block, parent *types.Block) *big.Int { +func CalcDifficulty(block, parent *types.Header) *big.Int { diff := new(big.Int) - adjust := new(big.Int).Rsh(parent.Difficulty(), 10) - if block.Time() >= parent.Time()+8 { - diff.Sub(parent.Difficulty(), adjust) + min := big.NewInt(2048) + adjust := new(big.Int).Div(parent.Difficulty, min) + if (block.Time - parent.Time) < 8 { + diff.Add(parent.Difficulty, adjust) } else { - diff.Add(parent.Difficulty(), adjust) + diff.Sub(parent.Difficulty, adjust) + } + + if diff.Cmp(GenesisDiff) < 0 { + return GenesisDiff } return diff @@ -122,7 +130,7 @@ func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlo self.mu.RLock() defer self.mu.RUnlock() - return self.td, self.currentBlock.Hash(), self.Genesis().Hash() + return self.td, self.currentBlock.Hash(), self.genesisBlock.Hash() } func (self *ChainManager) SetProcessor(proc types.BlockProcessor) { @@ -192,7 +200,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { coinbase, root, ethutil.BigPow(2, 32), - nil, + 0, "") block.SetUncles(nil) block.SetTransactions(nil) @@ -201,7 +209,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { parent := bc.currentBlock if parent != nil { header := block.Header() - header.Difficulty = CalcDifficulty(block, parent) + header.Difficulty = CalcDifficulty(block.Header(), parent.Header()) header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) header.GasLimit = CalcGasLimit(parent, block) @@ -373,9 +381,12 @@ func (bc *ChainManager) Stop() { } func (self *ChainManager) InsertChain(chain types.Blocks) error { + println("insert chain start") self.tsmu.Lock() defer self.tsmu.Unlock() + defer println("insert chain end") + for _, block := range chain { // Call in to the block processor and check for errors. It's likely that if one block fails // all others will fail too (unless a known block is returned). @@ -395,11 +406,11 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { var canonical, split bool self.mu.Lock() + cblock := self.currentBlock { // Write block to database. Eventually we'll have to improve on this and throw away blocks that are // not in the canonical chain. self.write(block) - cblock := self.currentBlock // Compare the TD of the last known block in the canonical chain to make sure it's greater. // At this point it's possible that a different chain (fork) becomes the new canonical chain. if td.Cmp(self.td) > 0 { @@ -417,8 +428,18 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.mu.Unlock() if canonical { + /* + jsonlogger.LogJson(&logger.EthChainNewHead{ + BlockHash: ethutil.Bytes2Hex(block.Hash()), + BlockNumber: block.Number(), + ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()), + BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()), + }) + */ self.setTransState(state.New(block.Root(), self.db)) self.eventMux.Post(ChainEvent{block, td}) + } else { + //self.eventMux. } if split { diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index bc3a264d1..b562b677d 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -3,6 +3,7 @@ package core import ( "bytes" "fmt" + "math/big" "os" "path" "runtime" @@ -21,6 +22,75 @@ func init() { ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH") } +// Test fork of length N starting from block i +func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) { + // switch databases to process the new chain + db, err := ethdb.NewMemDatabase() + if err != nil { + t.Fatal("Failed to create db:", err) + } + // copy old chain up to i into new db with deterministic canonical + bman2, err := newCanonical(i, db) + if err != nil { + t.Fatal("could not make new canonical in testFork", err) + } + // asert the bmans have the same block at i + bi1 := bman.bc.GetBlockByNumber(uint64(i)).Hash() + bi2 := bman2.bc.GetBlockByNumber(uint64(i)).Hash() + if bytes.Compare(bi1, bi2) != 0 { + t.Fatal("chains do not have the same hash at height", i) + } + + bman2.bc.SetProcessor(bman2) + + // extend the fork + parent := bman2.bc.CurrentBlock() + chainB := makeChain(bman2, parent, N, db, ForkSeed) + err = bman2.bc.InsertChain(chainB) + if err != nil { + t.Fatal("Insert chain error for fork:", err) + } + + tdpre := bman.bc.Td() + // Test the fork's blocks on the original chain + td, err := testChain(chainB, bman) + if err != nil { + t.Fatal("expected chainB not to give errors:", err) + } + // Compare difficulties + f(tdpre, td) +} + +func printChain(bc *ChainManager) { + for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- { + b := bc.GetBlockByNumber(uint64(i)) + fmt.Printf("\t%x\n", b.Hash()) + } +} + +// process blocks against a chain +func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) { + td := new(big.Int) + for _, block := range chainB { + td2, err := bman.bc.processor.Process(block) + if err != nil { + if IsKnownBlockErr(err) { + continue + } + return nil, err + } + block.Td = td2 + td = td2 + + bman.bc.mu.Lock() + { + bman.bc.write(block) + } + bman.bc.mu.Unlock() + } + return td, nil +} + func loadChain(fn string, t *testing.T) (types.Blocks, error) { fh, err := os.OpenFile(path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm) if err != nil { @@ -45,6 +115,130 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t * done <- true } +func TestExtendCanonical(t *testing.T) { + CanonicalLength := 5 + db, err := ethdb.NewMemDatabase() + if err != nil { + t.Fatal("Failed to create db:", err) + } + // make first chain starting from genesis + bman, err := newCanonical(CanonicalLength, db) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) <= 0 { + t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1) + } + } + // Start fork from current height (CanonicalLength) + testFork(t, bman, CanonicalLength, 1, f) + testFork(t, bman, CanonicalLength, 2, f) + testFork(t, bman, CanonicalLength, 5, f) + testFork(t, bman, CanonicalLength, 10, f) +} + +func TestShorterFork(t *testing.T) { + db, err := ethdb.NewMemDatabase() + if err != nil { + t.Fatal("Failed to create db:", err) + } + // make first chain starting from genesis + bman, err := newCanonical(10, db) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) >= 0 { + t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1) + } + } + // Sum of numbers must be less than 10 + // for this to be a shorter fork + testFork(t, bman, 0, 3, f) + testFork(t, bman, 0, 7, f) + testFork(t, bman, 1, 1, f) + testFork(t, bman, 1, 7, f) + testFork(t, bman, 5, 3, f) + testFork(t, bman, 5, 4, f) +} + +func TestLongerFork(t *testing.T) { + db, err := ethdb.NewMemDatabase() + if err != nil { + t.Fatal("Failed to create db:", err) + } + // make first chain starting from genesis + bman, err := newCanonical(10, db) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) <= 0 { + t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1) + } + } + // Sum of numbers must be greater than 10 + // for this to be a longer fork + testFork(t, bman, 0, 11, f) + testFork(t, bman, 0, 15, f) + testFork(t, bman, 1, 10, f) + testFork(t, bman, 1, 12, f) + testFork(t, bman, 5, 6, f) + testFork(t, bman, 5, 8, f) +} + +func TestEqualFork(t *testing.T) { + db, err := ethdb.NewMemDatabase() + if err != nil { + t.Fatal("Failed to create db:", err) + } + bman, err := newCanonical(10, db) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) != 0 { + t.Error("expected chainB to have equal difficulty. Got", td2, "expected ", td1) + } + } + // Sum of numbers must be equal to 10 + // for this to be an equal fork + testFork(t, bman, 0, 10, f) + testFork(t, bman, 1, 9, f) + testFork(t, bman, 2, 8, f) + testFork(t, bman, 5, 5, f) + testFork(t, bman, 6, 4, f) + testFork(t, bman, 9, 1, f) +} + +func TestBrokenChain(t *testing.T) { + db, err := ethdb.NewMemDatabase() + if err != nil { + t.Fatal("Failed to create db:", err) + } + bman, err := newCanonical(10, db) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } + db2, err := ethdb.NewMemDatabase() + if err != nil { + t.Fatal("Failed to create db:", err) + } + bman2, err := newCanonical(10, db2) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } + bman2.bc.SetProcessor(bman2) + parent := bman2.bc.CurrentBlock() + chainB := makeChain(bman2, parent, 5, db2, ForkSeed) + chainB = chainB[1:] + _, err = testChain(chainB, bman) + if err == nil { + t.Error("expected broken chain to return error") + } +} + func TestChainInsertions(t *testing.T) { t.Skip() // travil fails. diff --git a/core/error.go b/core/error.go index e86bacb2d..fb1eaed84 100644 --- a/core/error.go +++ b/core/error.go @@ -87,6 +87,24 @@ func IsNonceErr(err error) bool { return ok } +type InvalidTxErr struct { + Message string +} + +func (err *InvalidTxErr) Error() string { + return err.Message +} + +func InvalidTxError(err error) *InvalidTxErr { + return &InvalidTxErr{fmt.Sprintf("%v", err)} +} + +func IsInvalidTxErr(err error) bool { + _, ok := err.(*InvalidTxErr) + + return ok +} + type OutOfGasErr struct { Message string } diff --git a/core/execution.go b/core/execution.go index 5e0cbd37e..f7d5a8945 100644 --- a/core/execution.go +++ b/core/execution.go @@ -61,10 +61,10 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret snapshot := env.State().Copy() start := time.Now() ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input) + chainlogger.Debugf("vm took %v\n", time.Since(start)) if err != nil { env.State().Set(snapshot) } - chainlogger.Debugf("vm took %v\n", time.Since(start)) return } diff --git a/core/filter.go b/core/filter.go index c61c9e998..d58aa8d7c 100644 --- a/core/filter.go +++ b/core/filter.go @@ -147,7 +147,7 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs { // Filter the logs for interesting stuff Logs: for _, log := range logs { - if !includes(self.address, log.Address()) { + if len(self.address) > 0 && !includes(self.address, log.Address()) { continue } diff --git a/core/genesis.go b/core/genesis.go index decffc541..a3f5dfb38 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -22,12 +22,17 @@ var ZeroHash512 = make([]byte, 64) var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{})) var EmptyListRoot = crypto.Sha3(ethutil.Encode("")) +var GenesisDiff = big.NewInt(131072) + func GenesisBlock(db ethutil.Database) *types.Block { - genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, big.NewInt(131072), crypto.Sha3(big.NewInt(42).Bytes()), "") + genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, GenesisDiff, 42, "") genesis.Header().Number = ethutil.Big0 genesis.Header().GasLimit = big.NewInt(1000000) genesis.Header().GasUsed = ethutil.Big0 genesis.Header().Time = 0 + genesis.Header().SeedHash = make([]byte, 32) + genesis.Header().MixDigest = make([]byte, 32) + genesis.Td = ethutil.Big0 genesis.SetUncles([]*types.Header{}) @@ -55,6 +60,10 @@ func GenesisBlock(db ethutil.Database) *types.Block { } var genesisData = []byte(`{ + "0000000000000000000000000000000000000001": {"balance": "1"}, + "0000000000000000000000000000000000000002": {"balance": "1"}, + "0000000000000000000000000000000000000003": {"balance": "1"}, + "0000000000000000000000000000000000000004": {"balance": "1"}, "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, @@ -62,9 +71,5 @@ var genesisData = []byte(`{ "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": {"balance": "154162184000000000000000"}, - "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": {"balance": "102774789000000000000000"}, - "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": {"balance": "51387394000000000000000"}, - "b7576e9d314df41ec5506494293afb1bd5d3f65d": {"balance": "69423399000000000000000"} + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"} }`) diff --git a/core/state_transition.go b/core/state_transition.go index 7331fdd4a..00e383f3f 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -3,7 +3,6 @@ package core import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/state" @@ -12,6 +11,8 @@ import ( const tryJit = false +var () + /* * The State transitioning model * @@ -144,7 +145,7 @@ func (self *StateTransition) preCheck() (err error) { // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { - return err + return InvalidTxError(err) } return nil @@ -165,22 +166,22 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { defer self.RefundGas() - // Increment the nonce for the next transaction - self.state.SetNonce(sender.Address(), sender.Nonce()+1) - //sender.Nonce += 1 - // Transaction gas if err = self.UseGas(vm.GasTx); err != nil { - return + return nil, InvalidTxError(err) } + // Increment the nonce for the next transaction + self.state.SetNonce(sender.Address(), sender.Nonce()+1) + //sender.Nonce += 1 + // Pay data gas var dgas int64 for _, byt := range self.data { if byt != 0 { - dgas += vm.GasData.Int64() + dgas += vm.GasTxDataNonzeroByte.Int64() } else { - dgas += 1 // This is 1/5. If GasData changes this fails + dgas += vm.GasTxDataZeroByte.Int64() } } if err = self.UseGas(big.NewInt(dgas)); err != nil { diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 050cff3d8..bd377f679 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -117,8 +117,13 @@ func (self *TxPool) add(tx *types.Transaction) error { } else { to = "[NEW_CONTRACT]" } - - txplogger.Debugf("(t) %x => %s (%v) %x\n", tx.From()[:4], to, tx.Value, tx.Hash()) + var from string + if len(tx.From()) > 0 { + from = ethutil.Bytes2Hex(tx.From()[:4]) + } else { + return errors.New(fmt.Sprintf("FROM ADDRESS MUST BE POSITIVE (was %v)", tx.From())) + } + txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash()) // Notify the subscribers go self.eventMux.Post(TxPreEvent{tx}) diff --git a/core/types/block.go b/core/types/block.go index d57de1311..31c7c2b87 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "encoding/binary" "fmt" "math/big" "sort" @@ -39,14 +40,33 @@ type Header struct { Time uint64 // Extra data Extra string - // Block Nonce for verification - Nonce ethutil.Bytes + // SeedHash used for light client verification + SeedHash ethutil.Bytes + // Mix digest for quick checking to prevent DOS + MixDigest ethutil.Bytes + // Nonce + Nonce []byte } func (self *Header) rlpData(withNonce bool) []interface{} { - fields := []interface{}{self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra} + fields := []interface{}{ + self.ParentHash, + self.UncleHash, + self.Coinbase, + self.Root, + self.TxHash, + self.ReceiptHash, + self.Bloom, + self.Difficulty, + self.Number, + self.GasLimit, + self.GasUsed, + self.Time, + self.Extra, + self.SeedHash, + } if withNonce { - fields = append(fields, self.Nonce) + fields = append(fields, self.MixDigest, self.Nonce) } return fields @@ -77,24 +97,29 @@ type Block struct { Reward *big.Int } -func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce []byte, extra string) *Block { +func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce uint64, extra string) *Block { header := &Header{ Root: root, ParentHash: parentHash, Coinbase: coinbase, Difficulty: difficulty, - Nonce: nonce, Time: uint64(time.Now().Unix()), Extra: extra, GasUsed: new(big.Int), GasLimit: new(big.Int), } + header.setNonce(nonce) block := &Block{header: header, Reward: new(big.Int)} return block } +func (self *Header) setNonce(nonce uint64) { + self.Nonce = make([]byte, 8) + binary.BigEndian.PutUint64(self.Nonce, nonce) +} + func NewBlockWithHeader(header *Header) *Block { return &Block{header: header} } @@ -174,9 +199,17 @@ func (self *Block) RlpDataForStorage() interface{} { } // Header accessors (add as you need them) -func (self *Block) Number() *big.Int { return self.header.Number } -func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } -func (self *Block) Nonce() []byte { return self.header.Nonce } +func (self *Block) Number() *big.Int { return self.header.Number } +func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } +func (self *Block) MixDigest() []byte { return self.header.MixDigest } +func (self *Block) SeedHash() []byte { return self.header.SeedHash } +func (self *Block) Nonce() uint64 { + return binary.BigEndian.Uint64(self.header.Nonce) +} +func (self *Block) SetNonce(nonce uint64) { + self.header.setNonce(nonce) +} + func (self *Block) Bloom() []byte { return self.header.Bloom } func (self *Block) Coinbase() []byte { return self.header.Coinbase } func (self *Block) Time() int64 { return int64(self.header.Time) } @@ -200,7 +233,6 @@ func (self *Block) GetUncle(i int) *Header { // Implement pow.Block func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } -func (self *Block) N() []byte { return self.header.Nonce } func (self *Block) HashNoNonce() []byte { return self.header.HashNoNonce() } func (self *Block) Hash() []byte { @@ -249,8 +281,10 @@ func (self *Header) String() string { GasUsed: %v Time: %v Extra: %v - Nonce: %x -`, self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.Nonce) + SeedHash: %x + MixDigest: %x + Nonce: %x`, + self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.SeedHash, self.MixDigest, self.Nonce) } type Blocks []*Block diff --git a/core/types/bloom9.go b/core/types/bloom9.go index c1841e553..578265a34 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -14,7 +14,7 @@ func CreateBloom(receipts Receipts) []byte { bin.Or(bin, LogsBloom(receipt.logs)) } - return ethutil.LeftPadBytes(bin.Bytes(), 64) + return ethutil.LeftPadBytes(bin.Bytes(), 256) } func LogsBloom(logs state.Logs) *big.Int { @@ -37,9 +37,10 @@ func LogsBloom(logs state.Logs) *big.Int { func bloom9(b []byte) *big.Int { r := new(big.Int) - for _, i := range []int{0, 2, 4} { + + for i := 0; i < 16; i += 2 { t := big.NewInt(1) - b := uint(b[i+1]) + 256*(uint(b[i])&1) + b := uint(b[i+1]) + 1024*(uint(b[i])&1) r.Or(r, t.Lsh(t, b)) } |