From d056824683fb90094b5390dd3568d9d7f01634ee Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Tue, 1 Sep 2015 18:25:03 +0200 Subject: [PATCH 1/4] Ensure coinbase state object exists for each tx during block proc --- core/block_processor.go | 2 +- core/chain_makers.go | 4 ++-- core/state/statedb.go | 12 ++++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index 99d27fa717..d16bef8f6b 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -89,7 +89,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated } // Update the state with pending changes - statedb.SyncIntermediate() + statedb.SyncIntermediate(header.Coinbase, header.GasLimit) usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.Root().Bytes(), usedGas) diff --git a/core/chain_makers.go b/core/chain_makers.go index b009e0c28c..b826113668 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -93,7 +93,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { if err != nil { panic(err) } - b.statedb.SyncIntermediate() + b.statedb.SyncIntermediate(common.Address{}, b.header.GasLimit) b.header.GasUsed.Add(b.header.GasUsed, gas) receipt := types.NewReceipt(b.statedb.Root().Bytes(), b.header.GasUsed) logs := b.statedb.GetLogs(tx.Hash()) @@ -151,7 +151,7 @@ func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int, gen(i, b) } AccumulateRewards(statedb, h, b.uncles) - statedb.SyncIntermediate() + statedb.SyncIntermediate(h.Coinbase, h.GasLimit) h.Root = statedb.Root() return types.NewBlock(h, b.txs, b.uncles, b.receipts) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 577f7162eb..ca73618412 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -349,13 +349,21 @@ func (self *StateDB) Refunds() *big.Int { } // SyncIntermediate updates the intermediate state and all mid steps -func (self *StateDB) SyncIntermediate() { +func (self *StateDB) SyncIntermediate(headerCoinbase common.Address, headerGasLimit *big.Int) { self.refund = new(big.Int) for _, stateObject := range self.stateObjects { if stateObject.dirty { if stateObject.remove { - self.DeleteStateObject(stateObject) + if stateObject.address == headerCoinbase { + gasPoolCopy := new(big.Int).Set(stateObject.gasPool) + self.DeleteStateObject(stateObject) + coinbase := self.CreateAccount(headerCoinbase) + coinbase.SetGasLimit(headerGasLimit) + coinbase.gasPool = gasPoolCopy + } else { + self.DeleteStateObject(stateObject) + } } else { stateObject.Update() From 60b05b8780553eb3f77663bce663d12ab1f6579e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 1 Sep 2015 20:07:37 +0300 Subject: [PATCH 2/4] core: pass the coinbase directly instead of the header --- core/block_processor.go | 2 +- core/chain_makers.go | 4 ++-- core/state/state_test.go | 2 +- core/state/statedb.go | 14 ++++++++------ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index d16bef8f6b..b5f96f9a7f 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -89,7 +89,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated } // Update the state with pending changes - statedb.SyncIntermediate(header.Coinbase, header.GasLimit) + statedb.SyncIntermediate(coinbase) usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.Root().Bytes(), usedGas) diff --git a/core/chain_makers.go b/core/chain_makers.go index b826113668..1e33a6f574 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -93,7 +93,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { if err != nil { panic(err) } - b.statedb.SyncIntermediate(common.Address{}, b.header.GasLimit) + b.statedb.SyncIntermediate(b.coinbase) b.header.GasUsed.Add(b.header.GasUsed, gas) receipt := types.NewReceipt(b.statedb.Root().Bytes(), b.header.GasUsed) logs := b.statedb.GetLogs(tx.Hash()) @@ -151,7 +151,7 @@ func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int, gen(i, b) } AccumulateRewards(statedb, h, b.uncles) - statedb.SyncIntermediate(h.Coinbase, h.GasLimit) + statedb.SyncIntermediate(b.coinbase) h.Root = statedb.Root() return types.NewBlock(h, b.txs, b.uncles, b.receipts) } diff --git a/core/state/state_test.go b/core/state/state_test.go index 5972d266a9..bfe764ed72 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -88,7 +88,7 @@ func TestNull(t *testing.T) { //value := common.FromHex("0x823140710bf13990e4500136726d8b55") var value common.Hash state.SetState(address, common.Hash{}, value) - state.SyncIntermediate() + state.SyncIntermediate(nil) state.Sync() value = state.GetState(address, common.Hash{}) if !common.EmptyHash(value) { diff --git a/core/state/statedb.go b/core/state/statedb.go index ca73618412..c14a4893da 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -349,18 +349,20 @@ func (self *StateDB) Refunds() *big.Int { } // SyncIntermediate updates the intermediate state and all mid steps -func (self *StateDB) SyncIntermediate(headerCoinbase common.Address, headerGasLimit *big.Int) { +func (self *StateDB) SyncIntermediate(coinbase *StateObject) { self.refund = new(big.Int) for _, stateObject := range self.stateObjects { if stateObject.dirty { if stateObject.remove { - if stateObject.address == headerCoinbase { - gasPoolCopy := new(big.Int).Set(stateObject.gasPool) + if stateObject == coinbase { + // Save the original address and remaining gas + address, gas := coinbase.Address(), new(big.Int).Set(coinbase.gasPool) self.DeleteStateObject(stateObject) - coinbase := self.CreateAccount(headerCoinbase) - coinbase.SetGasLimit(headerGasLimit) - coinbase.gasPool = gasPoolCopy + + // Resurrect the coinbase and restore the gas allowance + *coinbase = *self.CreateAccount(address) + coinbase.SetGasLimit(gas) } else { self.DeleteStateObject(stateObject) } From ec8ece28f4924f7b42191046da1ace4f3f3923da Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Tue, 1 Sep 2015 19:28:51 +0200 Subject: [PATCH 3/4] Copy coinbase pointer --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index c14a4893da..ff2a4d6e76 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -361,7 +361,7 @@ func (self *StateDB) SyncIntermediate(coinbase *StateObject) { self.DeleteStateObject(stateObject) // Resurrect the coinbase and restore the gas allowance - *coinbase = *self.CreateAccount(address) + coinbase = self.CreateAccount(address) coinbase.SetGasLimit(gas) } else { self.DeleteStateObject(stateObject) From b26cf414730e45e1cacc9bfaf9a5c6317d6de8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 1 Sep 2015 21:13:47 +0300 Subject: [PATCH 4/4] core, miner: use coinbase references to allow resurrection --- core/block_processor.go | 14 ++++++-------- core/chain_makers.go | 4 ++-- core/state/statedb.go | 11 +++++------ miner/worker.go | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index b5f96f9a7f..04b469eb91 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -73,23 +73,21 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block coinbase.SetGasLimit(block.GasLimit()) // Process the transactions on to parent state - receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) + receipts, err = sm.ApplyTransactions(&coinbase, statedb, block, block.Transactions(), transientProcess) if err != nil { return nil, err } - return receipts, nil } -func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { - cb := statedb.GetStateObject(coinbase.Address()) +func (self *BlockProcessor) ApplyTransaction(coinbasePtr **state.StateObject, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { + cb := statedb.GetStateObject((*coinbasePtr).Address()) _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, cb) if err != nil { return nil, nil, err } - // Update the state with pending changes - statedb.SyncIntermediate(coinbase) + statedb.SyncIntermediate(coinbasePtr) usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.Root().Bytes(), usedGas) @@ -118,7 +116,7 @@ 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, error) { +func (self *BlockProcessor) ApplyTransactions(coinbasePtr **state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) { var ( receipts types.Receipts totalUsedGas = big.NewInt(0) @@ -130,7 +128,7 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state for i, tx := range txs { statedb.StartRecord(tx.Hash(), block.Hash(), i) - receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, header, tx, totalUsedGas, transientProcess) + receipt, txGas, err := self.ApplyTransaction(coinbasePtr, statedb, header, tx, totalUsedGas, transientProcess) if err != nil { return nil, err } diff --git a/core/chain_makers.go b/core/chain_makers.go index 1e33a6f574..401622ddd2 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -93,7 +93,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { if err != nil { panic(err) } - b.statedb.SyncIntermediate(b.coinbase) + b.statedb.SyncIntermediate(&b.coinbase) b.header.GasUsed.Add(b.header.GasUsed, gas) receipt := types.NewReceipt(b.statedb.Root().Bytes(), b.header.GasUsed) logs := b.statedb.GetLogs(tx.Hash()) @@ -151,7 +151,7 @@ func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int, gen(i, b) } AccumulateRewards(statedb, h, b.uncles) - statedb.SyncIntermediate(b.coinbase) + statedb.SyncIntermediate(&b.coinbase) h.Root = statedb.Root() return types.NewBlock(h, b.txs, b.uncles, b.receipts) } diff --git a/core/state/statedb.go b/core/state/statedb.go index ff2a4d6e76..44aab13573 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -349,26 +349,25 @@ func (self *StateDB) Refunds() *big.Int { } // SyncIntermediate updates the intermediate state and all mid steps -func (self *StateDB) SyncIntermediate(coinbase *StateObject) { +func (self *StateDB) SyncIntermediate(coinbaseRef **StateObject) { self.refund = new(big.Int) for _, stateObject := range self.stateObjects { if stateObject.dirty { if stateObject.remove { - if stateObject == coinbase { + if stateObject == (*coinbaseRef) { // Save the original address and remaining gas - address, gas := coinbase.Address(), new(big.Int).Set(coinbase.gasPool) + address, gas := (*coinbaseRef).Address(), new(big.Int).Set((*coinbaseRef).gasPool) self.DeleteStateObject(stateObject) // Resurrect the coinbase and restore the gas allowance - coinbase = self.CreateAccount(address) - coinbase.SetGasLimit(gas) + *coinbaseRef = self.CreateAccount(address) + (*coinbaseRef).SetGasLimit(gas) } else { self.DeleteStateObject(stateObject) } } else { stateObject.Update() - self.UpdateStateObject(stateObject) } stateObject.dirty = false diff --git a/miner/worker.go b/miner/worker.go index 86970ec071..1f7ad04632 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -619,7 +619,7 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b func (env *Work) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor) error { snap := env.state.Copy() - receipt, _, err := proc.ApplyTransaction(env.coinbase, env.state, env.header, tx, env.header.GasUsed, true) + receipt, _, err := proc.ApplyTransaction(&env.coinbase, env.state, env.header, tx, env.header.GasUsed, true) if err != nil { env.state.Set(snap) return err