From 2da367a2bee84d74d1bb0ea1b42d4c22fae486dd Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 26 Jan 2015 10:57:23 -0800 Subject: fix unchecked slice index on tx.From() --- core/transaction_pool.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'core') diff --git a/core/transaction_pool.go b/core/transaction_pool.go index d3aec9050..193db45ed 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -109,8 +109,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 { + from = "INVALID" + } + txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash()) // Notify the subscribers go self.eventMux.Post(TxPreEvent{tx}) -- cgit From 9446489cf3f2eb4b5237b9355b3975fde2886508 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 17 Feb 2015 22:02:15 -0500 Subject: core: chain manager forking tests --- core/chain_manager_test.go | 276 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) (limited to 'core') diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index bc3a264d1..a357a8b1a 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" @@ -13,14 +14,167 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/rlp" + "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{}) []byte { return nil } +func (f fakePow) Verify(block pow.Block) bool { return true } +func (f fakePow) GetHashrate() int64 { return 0 } +func (f fakePow) Turbo(bool) {} + func init() { runtime.GOMAXPROCS(runtime.NumCPU()) ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH") } +func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { + block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), nil, "") + + block.SetUncles(nil) + block.SetTransactions(nil) + block.SetReceipts(nil) + + header := block.Header() + header.Difficulty = CalcDifficulty(block, parent) + header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) + header.GasLimit = CalcGasLimit(parent, block) + + block.Td = parent.Td + + return block +} + +// Actually make a block by simulating what miner would do +func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block { + addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) + block := newBlockFromParent(addr, parent) + state := state.New(block.Root(), db) + cbase := state.GetOrNewStateObject(addr) + cbase.SetGasPool(CalcGasLimit(parent, block)) + cbase.AddAmount(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) types.Blocks { + bman.bc.currentBlock = parent + blocks := make(types.Blocks, max) + for i := 0; i < max; i++ { + block := makeBlock(bman, parent, i, db) + 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 + fmt.Printf("New Block: %x\n", block.Hash()) + } + fmt.Println("Done making chain") + 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, txpool, newChainManager(nil, eventMux, db), eventMux) + bman.Pow = fakePow{} + return bman +} + +// Make a new 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) + bman.bc.InsertChain(lchain) + return bman, nil +} + +// 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)) { + fmt.Println("Testing Fork!") + var b *types.Block = nil + if i > 0 { + b = bman.bc.GetBlockByNumber(uint64(i)) + } + _ = b + // 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) + } + bman2.bc.SetProcessor(bman2) + + parent := bman2.bc.CurrentBlock() + chainB := makeChain(bman2, parent, N, db) + bman2.bc.InsertChain(chainB) + + tdpre := bman.bc.Td() + td, err := testChain(chainB, bman) + if err != nil { + t.Fatal("expected chainB not to give errors:", err) + } + // Compare difficulties + f(tdpre, td) +} + +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 +199,128 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t * done <- true } +func TestExtendCanonical(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(5, 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 (5) + testFork(t, bman, 5, 1, f) + testFork(t, bman, 5, 2, f) + testFork(t, bman, 5, 5, f) + testFork(t, bman, 5, 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, 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) + 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. -- cgit From 483d96a89d68023360d211ab329400f4b960fe48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 22 Feb 2015 13:12:01 +0100 Subject: Added eth_logs & fixed issue with manual log filtering * Implemented `eth_logs` * Fixed issue with `filter.Find()` where logs were appended to an incorrect, non-returned slice resulting in no logs found --- core/block_processor.go | 16 ++++++---------- core/filter.go | 5 ++--- 2 files changed, 8 insertions(+), 13 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index bfd9d4560..fd591a29d 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -60,12 +60,12 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM return sm } -func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) { +func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) { coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase) coinbase.SetGasPool(CalcGasLimit(parent, block)) // Process the transactions on to parent state - receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false) + receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) if err != nil { return nil, err } @@ -100,10 +100,9 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated // Notify all subscribers if !transientProcess { go self.eventMux.Post(TxPostEvent{tx}) + go self.eventMux.Post(statedb.Logs()) } - go self.eventMux.Post(statedb.Logs()) - return receipt, txGas, err } @@ -179,7 +178,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big return } - receipts, err := sm.TransitionState(state, parent, block) + receipts, err := sm.TransitionState(state, parent, block, false) if err != nil { return } @@ -316,13 +315,10 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro var ( parent = sm.bc.GetBlock(block.Header().ParentHash) - //state = state.New(parent.Trie().Copy()) - state = state.New(parent.Root(), sm.db) + state = state.New(parent.Root(), sm.db) ) - defer state.Reset() - - sm.TransitionState(state, parent, block) + sm.TransitionState(state, parent, block, true) sm.AccumulateRewards(state, block, parent) return state.Logs(), nil diff --git a/core/filter.go b/core/filter.go index 88f12a67c..cdf7b282d 100644 --- a/core/filter.go +++ b/core/filter.go @@ -111,14 +111,14 @@ func (self *Filter) Find() state.Logs { // current parameters if self.bloomFilter(block) { // Get the logs of the block - logs, err := self.eth.BlockProcessor().GetLogs(block) + unfiltered, err := self.eth.BlockProcessor().GetLogs(block) if err != nil { chainlogger.Warnln("err: filter get logs ", err) break } - logs = append(logs, self.FilterLogs(logs)...) + logs = append(logs, self.FilterLogs(unfiltered)...) } block = self.eth.ChainManager().GetBlock(block.ParentHash()) @@ -146,7 +146,6 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs { Logs: for _, log := range logs { if !includes(self.address, log.Address()) { - //if !bytes.Equal(self.address, log.Address()) { continue } -- cgit From b2a225a52e45315f3ec90e11707fefa6059d13f5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Feb 2015 15:43:41 +0100 Subject: Properly uninstall filters. Mining issue fixed #closes #365 * Added an additional tx state which is used to get the current nonce * Refresh transient state each time a new canonical block is found * Properly uninstall filters. Fixes a possible crash in RPC --- core/chain_manager.go | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'core') diff --git a/core/chain_manager.go b/core/chain_manager.go index 9ef091c3c..4c7db6e2e 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -85,12 +85,14 @@ type ChainManager struct { lastBlockHash []byte transState *state.StateDB + txState *state.StateDB } func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux} bc.setLastBlock() bc.transState = bc.State().Copy() + bc.txState = bc.State().Copy() return bc } @@ -138,6 +140,19 @@ func (self *ChainManager) TransState() *state.StateDB { return self.transState } +func (self *ChainManager) TxState() *state.StateDB { + self.tsmu.RLock() + defer self.tsmu.RUnlock() + + return self.txState +} + +func (self *ChainManager) setTxState(state *state.StateDB) { + self.tsmu.Lock() + defer self.tsmu.Unlock() + self.txState = state +} + func (self *ChainManager) setTransState(statedb *state.StateDB) { self.transState = statedb } @@ -363,6 +378,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { defer self.tsmu.Unlock() 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). td, err := self.processor.Process(block) if err != nil { if IsKnownBlockErr(err) { @@ -377,11 +394,15 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } block.Td = td - var chain, split bool + var canonical, split bool self.mu.Lock() { + // 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 { if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 { chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td) @@ -391,17 +412,18 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.setTotalDifficulty(td) self.insert(block) - chain = true + canonical = true } } self.mu.Unlock() - if chain { + if canonical { + self.setTransState(state.New(block.Root(), self.db)) self.eventMux.Post(ChainEvent{block, td}) } if split { - self.setTransState(state.New(block.Root(), self.db)) + self.setTxState(state.New(block.Root(), self.db)) self.eventMux.Post(ChainSplitEvent{block}) } } -- cgit From 0b57bad2de08f382c1b36045db4c66b84d207d3b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Feb 2015 19:25:41 +0100 Subject: removed log --- core/chain_manager.go | 1 - 1 file changed, 1 deletion(-) (limited to 'core') diff --git a/core/chain_manager.go b/core/chain_manager.go index 9ef091c3c..38d1d64b4 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -268,7 +268,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain break } } - fmt.Printf("get hash %x (%d)\n", hash, len(chain)) return } -- cgit From 260ab739694b554c3cdec8531b98e0334753fbe1 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 25 Feb 2015 20:00:32 +0100 Subject: Validate block header gas limit * Add block header gas limit validation in ValidateBlock function, see eq 39 and 45 in yellow paper. Before it was calculated _for_ the block instead of validated. * Use the block header gas limit when setting the gas pool instead of calculating the value for the block. --- core/block_processor.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index fd591a29d..f66d158b2 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -62,7 +62,7 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) { coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase) - coinbase.SetGasPool(CalcGasLimit(parent, block)) + coinbase.SetGasPool(block.Header().GasLimit) // Process the transactions on to parent state receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) @@ -247,6 +247,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().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) + } + if block.Time() < parent.Time() { return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time) } -- cgit From e235b57234a68a8a39cfe7691a1825d8c6bb3443 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 18:39:05 +0100 Subject: Fixed consensus issue for refunding * Refund should _always_ go to the origin --- core/block_processor.go | 8 ++++---- core/state_transition.go | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index f66d158b2..7eaeb5be0 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -48,9 +48,8 @@ type BlockProcessor struct { func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor { sm := &BlockProcessor{ - db: db, - mem: make(map[string]*big.Int), - //Pow: ðash.Ethash{}, + db: db, + mem: make(map[string]*big.Int), Pow: ezp.New(), bc: chainManager, eventMux: eventMux, @@ -100,7 +99,8 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated // Notify all subscribers if !transientProcess { go self.eventMux.Post(TxPostEvent{tx}) - go self.eventMux.Post(statedb.Logs()) + logs := statedb.Logs() + go self.eventMux.Post(logs) } return receipt, txGas, err diff --git a/core/state_transition.go b/core/state_transition.go index 36ffa23d9..a065c4f6b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -126,7 +126,7 @@ func (self *StateTransition) BuyGas() error { self.AddGas(self.msg.Gas()) self.initialGas.Set(self.msg.Gas()) - sender.SubAmount(MessageGasValue(self.msg)) + sender.SubBalance(MessageGasValue(self.msg)) return nil } @@ -251,13 +251,16 @@ func (self *StateTransition) RefundGas() { coinbase, sender := self.Coinbase(), self.From() // Return remaining gas remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice()) - sender.AddAmount(remaining) + fmt.Println("REFUND:", remaining) + sender.AddBalance(remaining) uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2) for addr, ref := range self.state.Refunds() { refund := ethutil.BigMin(uhalf, ref) self.gas.Add(self.gas, refund) - self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) + addToIt := refund.Mul(refund, self.msg.GasPrice()) + fmt.Println("ADD TO IT", addToIt) + self.state.AddBalance([]byte(addr), addToIt) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) -- cgit From 3ab05ddd25aa805510ac304c1fd8f7c5c620dff4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 20:26:37 +0100 Subject: Bump --- core/state_transition.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'core') diff --git a/core/state_transition.go b/core/state_transition.go index a065c4f6b..7331fdd4a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -251,16 +251,13 @@ func (self *StateTransition) RefundGas() { coinbase, sender := self.Coinbase(), self.From() // Return remaining gas remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice()) - fmt.Println("REFUND:", remaining) sender.AddBalance(remaining) uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2) for addr, ref := range self.state.Refunds() { refund := ethutil.BigMin(uhalf, ref) self.gas.Add(self.gas, refund) - addToIt := refund.Mul(refund, self.msg.GasPrice()) - fmt.Println("ADD TO IT", addToIt) - self.state.AddBalance([]byte(addr), addToIt) + self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) -- cgit From 0efd6a881afac0b3082f3b1e8780e3438eea5b02 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 27 Feb 2015 16:05:03 -0500 Subject: public functions for making chains on the fly --- core/chain_makers.go | 131 +++++++++++++++++++++++++++++++++++++++++++++ core/chain_manager_test.go | 96 --------------------------------- 2 files changed, 131 insertions(+), 96 deletions(-) create mode 100644 core/chain_makers.go (limited to 'core') diff --git a/core/chain_makers.go b/core/chain_makers.go new file mode 100644 index 000000000..eb43f8aa0 --- /dev/null +++ b/core/chain_makers.go @@ -0,0 +1,131 @@ +package core + +import ( + "fmt" + "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" + "math/big" +) + +// So we can generate blocks easily +type FakePow struct{} + +func (f FakePow) Search(block pow.Block, stop <-chan struct{}) []byte { return nil } +func (f FakePow) Verify(block pow.Block) bool { return true } +func (f FakePow) GetHashrate() int64 { return 0 } +func (f FakePow) Turbo(bool) {} + +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) *types.Block { + return makeBlock(bman, parent, i, db) +} + +func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database) types.Blocks { + return makeChain(bman, parent, max, db) +} + +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) +} + +func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { + block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), nil, "") + + block.SetUncles(nil) + block.SetTransactions(nil) + block.SetReceipts(nil) + + header := block.Header() + header.Difficulty = CalcDifficulty(block, parent) + header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) + header.GasLimit = CalcGasLimit(parent, block) + + block.Td = parent.Td + + return block +} + +// Actually make a block by simulating what miner would do +func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block { + addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) + 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) types.Blocks { + bman.bc.currentBlock = parent + blocks := make(types.Blocks, max) + for i := 0; i < max; i++ { + block := makeBlock(bman, parent, i, db) + 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 + fmt.Printf("New Block: %x\n", block.Hash()) + } + fmt.Println("Done making chain") + 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, txpool, newChainManager(nil, eventMux, db), eventMux) + bman.Pow = FakePow{} + return bman +} + +// Make a new 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) + bman.bc.InsertChain(lchain) + return bman, nil +} diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index a357a8b1a..b76ac187c 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -19,107 +19,11 @@ import ( "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{}) []byte { return nil } -func (f fakePow) Verify(block pow.Block) bool { return true } -func (f fakePow) GetHashrate() int64 { return 0 } -func (f fakePow) Turbo(bool) {} - func init() { runtime.GOMAXPROCS(runtime.NumCPU()) ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH") } -func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { - block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), nil, "") - - block.SetUncles(nil) - block.SetTransactions(nil) - block.SetReceipts(nil) - - header := block.Header() - header.Difficulty = CalcDifficulty(block, parent) - header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) - header.GasLimit = CalcGasLimit(parent, block) - - block.Td = parent.Td - - return block -} - -// Actually make a block by simulating what miner would do -func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block { - addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) - block := newBlockFromParent(addr, parent) - state := state.New(block.Root(), db) - cbase := state.GetOrNewStateObject(addr) - cbase.SetGasPool(CalcGasLimit(parent, block)) - cbase.AddAmount(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) types.Blocks { - bman.bc.currentBlock = parent - blocks := make(types.Blocks, max) - for i := 0; i < max; i++ { - block := makeBlock(bman, parent, i, db) - 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 - fmt.Printf("New Block: %x\n", block.Hash()) - } - fmt.Println("Done making chain") - 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, txpool, newChainManager(nil, eventMux, db), eventMux) - bman.Pow = fakePow{} - return bman -} - -// Make a new 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) - bman.bc.InsertChain(lchain) - return bman, nil -} - // 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)) { fmt.Println("Testing Fork!") -- cgit