diff options
author | Felix Lange <fjl@twurst.com> | 2015-06-16 18:41:50 +0800 |
---|---|---|
committer | Jeffrey Wilcke <geffobscura@gmail.com> | 2015-06-30 00:51:47 +0800 |
commit | 1d42888d3047dabfb352c94a2051e7af14d2a509 (patch) | |
tree | 8ca68ca98bd697f26f2033a5480e78ccbf064162 /core | |
parent | 654564e164b3b6f7f4ba1e8bbd6fcd64776068fa (diff) | |
download | go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar.gz go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar.zst go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.zip |
core/types: make blocks immutable
Diffstat (limited to 'core')
-rw-r--r-- | core/block_cache_test.go | 6 | ||||
-rw-r--r-- | core/block_processor.go | 95 | ||||
-rw-r--r-- | core/block_processor_test.go | 16 | ||||
-rw-r--r-- | core/chain_makers.go | 58 | ||||
-rw-r--r-- | core/chain_manager.go | 94 | ||||
-rw-r--r-- | core/chain_manager_test.go | 30 | ||||
-rw-r--r-- | core/genesis.go | 37 | ||||
-rw-r--r-- | core/state_transition.go | 9 | ||||
-rw-r--r-- | core/transaction_pool.go | 2 | ||||
-rw-r--r-- | core/types/block.go | 421 | ||||
-rw-r--r-- | core/vm_env.go | 34 |
11 files changed, 343 insertions, 459 deletions
diff --git a/core/block_cache_test.go b/core/block_cache_test.go index 43ab847f9..80d118599 100644 --- a/core/block_cache_test.go +++ b/core/block_cache_test.go @@ -11,12 +11,12 @@ import ( func newChain(size int) (chain []*types.Block) { var parentHash common.Hash for i := 0; i < size; i++ { - block := types.NewBlock(parentHash, common.Address{}, common.Hash{}, new(big.Int), 0, nil) - block.Header().Number = big.NewInt(int64(i)) + head := &types.Header{ParentHash: parentHash, Number: big.NewInt(int64(i))} + block := types.NewBlock(head, nil, nil, nil) chain = append(chain, block) parentHash = block.Hash() } - return + return chain } func insertChainCache(cache *BlockCache, chain []*types.Block) { diff --git a/core/block_processor.go b/core/block_processor.go index e30ced312..2fd8c04c0 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -57,8 +57,8 @@ func NewBlockProcessor(db, extra common.Database, pow pow.PoW, chainManager *Cha } 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.SetGasLimit(block.Header().GasLimit) + coinbase := statedb.GetOrNewStateObject(block.Coinbase()) + coinbase.SetGasLimit(block.GasLimit()) // Process the transactions on to parent state receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) @@ -69,11 +69,11 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block return receipts, nil } -func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { +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) { // If we are mining this block and validating we want to set the logs back to 0 cb := statedb.GetStateObject(coinbase.Address()) - _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb) + _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, cb) if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) { return nil, nil, err } @@ -108,12 +108,13 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state totalUsedGas = big.NewInt(0) err error cumulativeSum = new(big.Int) + header = block.Header() ) for i, tx := range txs { statedb.StartRecord(tx.Hash(), block.Hash(), i) - receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess) + receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, header, tx, totalUsedGas, transientProcess) if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) { return nil, err } @@ -142,11 +143,10 @@ func (sm *BlockProcessor) RetryProcess(block *types.Block) (logs state.Logs, err sm.mutex.Lock() defer sm.mutex.Unlock() - header := block.Header() - if !sm.bc.HasBlock(header.ParentHash) { - return nil, ParentError(header.ParentHash) + if !sm.bc.HasBlock(block.ParentHash()) { + return nil, ParentError(block.ParentHash()) } - parent := sm.bc.GetBlock(header.ParentHash) + parent := sm.bc.GetBlock(block.ParentHash()) // FIXME Change to full header validation. See #1225 errch := make(chan bool) @@ -168,30 +168,32 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, err erro sm.mutex.Lock() defer sm.mutex.Unlock() - header := block.Header() - if sm.bc.HasBlock(header.Hash()) { - return nil, &KnownBlockError{header.Number, header.Hash()} + if sm.bc.HasBlock(block.Hash()) { + return nil, &KnownBlockError{block.Number(), block.Hash()} } - if !sm.bc.HasBlock(header.ParentHash) { - return nil, ParentError(header.ParentHash) + if !sm.bc.HasBlock(block.ParentHash()) { + return nil, ParentError(block.ParentHash()) } - parent := sm.bc.GetBlock(header.ParentHash) + parent := sm.bc.GetBlock(block.ParentHash()) return sm.processWithParent(block, parent) } func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) { // Create a new state based on the parent's root (e.g., create copy) state := state.New(parent.Root(), sm.db) + header := block.Header() + uncles := block.Uncles() + txs := block.Transactions() // Block validation - if err = ValidateHeader(sm.Pow, block.Header(), parent.Header(), false); err != nil { + if err = ValidateHeader(sm.Pow, header, parent.Header(), false); err != nil { return } // There can be at most two uncles - if len(block.Uncles()) > 2 { - return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles())) + if len(uncles) > 2 { + return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(uncles)) } receipts, err := sm.TransitionState(state, parent, block, false) @@ -199,8 +201,6 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st return } - header := block.Header() - // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. rbloom := types.CreateBloom(receipts) @@ -211,7 +211,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st // The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]])) // can be used by light clients to make sure they've received the correct Txs - txSha := types.DeriveSha(block.Transactions()) + txSha := types.DeriveSha(txs) if txSha != header.TxHash { err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha) return @@ -225,7 +225,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st } // Verify UncleHash before running other uncle validations - unclesSha := block.CalculateUnclesHash() + unclesSha := types.CalcUncleHash(uncles) if unclesSha != header.UncleHash { err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha) return @@ -236,7 +236,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st return } // Accumulate static rewards; block reward, uncle's and uncle inclusion. - AccumulateRewards(state, block) + AccumulateRewards(state, header, uncles) // Commit state objects/accounts to a temporary trie (does not save) // used to calculate the state root. @@ -260,11 +260,34 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st return state.Logs(), nil } +// AccumulateRewards credits the coinbase of the given block with the +// mining reward. The total reward consists of the static block reward +// and rewards for included uncles. +func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) { + reward := new(big.Int).Set(BlockReward) + + for _, uncle := range uncles { + num := new(big.Int).Add(big.NewInt(8), uncle.Number) + num.Sub(num, header.Number) + + r := new(big.Int) + r.Mul(BlockReward, num) + r.Div(r, big.NewInt(8)) + + statedb.AddBalance(uncle.Coinbase, r) + + reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) + } + + // Get the account associated with the coinbase + statedb.AddBalance(header.Coinbase, reward) +} + func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error { ancestors := set.New() uncles := set.New() ancestorHeaders := make(map[common.Hash]*types.Header) - for _, ancestor := range sm.bc.GetAncestors(block, 7) { + for _, ancestor := range sm.bc.GetBlocksFromHash(block.ParentHash(), 7) { ancestorHeaders[ancestor.Hash()] = ancestor.Header() ancestors.Add(ancestor.Hash()) // Include ancestors uncles in the uncle set. Uncles must be unique. @@ -325,7 +348,7 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro // TODO: remove backward compatibility var ( - parent = sm.bc.GetBlock(block.Header().ParentHash) + parent = sm.bc.GetBlock(block.ParentHash()) state = state.New(parent.Root(), sm.db) ) @@ -341,7 +364,7 @@ func ValidateHeader(pow pow.PoW, block, parent *types.Header, checkPow bool) err return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) } - expd := CalcDifficulty(block, parent) + expd := CalcDifficulty(int64(block.Time), int64(parent.Time), parent.Difficulty) if expd.Cmp(block.Difficulty) != 0 { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) } @@ -375,26 +398,6 @@ func ValidateHeader(pow pow.PoW, block, parent *types.Header, checkPow bool) err return nil } -func AccumulateRewards(statedb *state.StateDB, block *types.Block) { - reward := new(big.Int).Set(BlockReward) - - for _, uncle := range block.Uncles() { - num := new(big.Int).Add(big.NewInt(8), uncle.Number) - num.Sub(num, block.Number()) - - r := new(big.Int) - r.Mul(BlockReward, num) - r.Div(r, big.NewInt(8)) - - statedb.AddBalance(uncle.Coinbase, r) - - reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) - } - - // Get the account associated with the coinbase - statedb.AddBalance(block.Header().Coinbase, reward) -} - func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) { var rdata []byte rdata, err = db.Get(append(receiptsPre, bhash[:]...)) diff --git a/core/block_processor_test.go b/core/block_processor_test.go index e38c815ef..bd77a2fc2 100644 --- a/core/block_processor_test.go +++ b/core/block_processor_test.go @@ -26,20 +26,18 @@ func proc() (*BlockProcessor, *ChainManager) { } func TestNumber(t *testing.T) { - _, chain := proc() - block1 := chain.NewBlock(common.Address{}) - block1.Header().Number = big.NewInt(3) - block1.Header().Time-- - pow := ezp.New() - err := ValidateHeader(pow, block1.Header(), chain.Genesis().Header(), false) + bp, chain := proc() + header := makeHeader(chain.Genesis(), 0, bp.db, 0) + header.Number = big.NewInt(3) + err := ValidateHeader(pow, header, chain.Genesis().Header(), false) if err != BlockNumberErr { - t.Errorf("expected block number error %v", err) + t.Errorf("expected block number error, got %q", err) } - block1 = chain.NewBlock(common.Address{}) - err = ValidateHeader(pow, block1.Header(), chain.Genesis().Header(), false) + header = makeHeader(chain.Genesis(), 0, bp.db, 0) + err = ValidateHeader(pow, header, chain.Genesis().Header(), false) if err == BlockNumberErr { t.Errorf("didn't expect block number error") } diff --git a/core/chain_makers.go b/core/chain_makers.go index 76acfd6ca..e704fd088 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -29,12 +29,8 @@ var ( // Utility functions for making chains on the fly // Exposed for sake of testing from other packages (eg. go-ethash) -func NewBlockFromParent(addr common.Address, parent *types.Block) *types.Block { - return newBlockFromParent(addr, parent) -} - func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Database, seed int) *types.Block { - return makeBlock(bman, parent, i, db, seed) + return types.NewBlock(makeHeader(parent, i, db, seed), nil, nil, nil) } func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Database, seed int) types.Blocks { @@ -53,46 +49,38 @@ func NewCanonical(n int, db common.Database) (*BlockProcessor, error) { return newCanonical(n, db) } -// block time is fixed at 10 seconds -func newBlockFromParent(addr common.Address, parent *types.Block) *types.Block { - block := types.NewBlock(parent.Hash(), addr, parent.Root(), common.BigPow(2, 32), 0, nil) - 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, common.Big1) - header.Time = parent.Header().Time + 10 - header.GasLimit = CalcGasLimit(parent) - - 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 common.Database, seed int) *types.Block { +// makeHeader creates the header for a new empty block, simulating +// what miner would do. We seed chains by the first byte of the coinbase. +func makeHeader(parent *types.Block, i int, db common.Database, seed int) *types.Header { var addr common.Address - addr[0], addr[19] = byte(seed), byte(i) - block := newBlockFromParent(addr, parent) - state := state.New(block.Root(), db) + addr[0], addr[19] = byte(seed), byte(i) // 'random' coinbase + time := parent.Time() + 10 // block time is fixed at 10 seconds + + // ensure that the block's coinbase has the block reward in the state. + state := state.New(parent.Root(), db) cbase := state.GetOrNewStateObject(addr) cbase.SetGasLimit(CalcGasLimit(parent)) cbase.AddBalance(BlockReward) state.Update() - block.SetRoot(state.Root()) - return block + + return &types.Header{ + Root: state.Root(), + ParentHash: parent.Hash(), + Coinbase: addr, + Difficulty: CalcDifficulty(time, parent.Time(), parent.Difficulty()), + Number: new(big.Int).Add(parent.Number(), common.Big1), + Time: uint64(time), + GasLimit: CalcGasLimit(parent), + } } -// Make a chain with real blocks -// Runs ProcessWithParent to get proper state roots +// makeChain creates a valid chain of empty blocks. func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.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) + block := types.NewBlock(makeHeader(parent, i, db, seed), nil, nil, nil) + // Use ProcessWithParent to verify that we have produced a valid block. _, err := bman.processWithParent(block, parent) if err != nil { fmt.Println("process with parent failed", err) @@ -129,7 +117,7 @@ func newBlockProcessor(db common.Database, cman *ChainManager, eventMux *event.T } // Make a new, deterministic canonical chain by running InsertChain -// on result of makeChain +// on result of makeChain. func newCanonical(n int, db common.Database) (*BlockProcessor, error) { eventMux := &event.TypeMux{} diff --git a/core/chain_manager.go b/core/chain_manager.go index 3b9b7517b..8a79e3e8a 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -38,23 +38,24 @@ const ( maxTimeFutureBlocks = 30 ) -func CalcDifficulty(block, parent *types.Header) *big.Int { +// CalcDifficulty is the difficulty adjustment algorithm. It returns +// the difficulty that a new block b should have when created at time +// given the parent block's time and difficulty. +func CalcDifficulty(time int64, parentTime int64, parentDiff *big.Int) *big.Int { diff := new(big.Int) - - adjust := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) - if big.NewInt(int64(block.Time)-int64(parent.Time)).Cmp(params.DurationLimit) < 0 { - diff.Add(parent.Difficulty, adjust) + adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor) + if big.NewInt(time-parentTime).Cmp(params.DurationLimit) < 0 { + diff.Add(parentDiff, adjust) } else { - diff.Sub(parent.Difficulty, adjust) + diff.Sub(parentDiff, adjust) } - if diff.Cmp(params.MinimumDifficulty) < 0 { return params.MinimumDifficulty } - return diff } +// CalcTD computes the total difficulty of block. func CalcTD(block, parent *types.Block) *big.Int { if parent == nil { return block.Difficulty() @@ -62,6 +63,8 @@ func CalcTD(block, parent *types.Block) *big.Int { return new(big.Int).Add(parent.Td, block.Header().Difficulty) } +// CalcGasLimit computes the gas limit of the next block after parent. +// The result may be modified by the caller. func CalcGasLimit(parent *types.Block) *big.Int { decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor) contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3)) @@ -71,11 +74,11 @@ func CalcGasLimit(parent *types.Block) *big.Int { gl := new(big.Int).Sub(parent.GasLimit(), decay) gl = gl.Add(gl, contrib) gl = gl.Add(gl, big.NewInt(1)) - gl = common.BigMax(gl, params.MinGasLimit) + gl.Set(common.BigMax(gl, params.MinGasLimit)) if gl.Cmp(params.GenesisGasLimit) < 0 { - gl2 := new(big.Int).Add(parent.GasLimit(), decay) - return common.BigMin(params.GenesisGasLimit, gl2) + gl.Add(parent.GasLimit(), decay) + gl.Set(common.BigMin(gl, params.GenesisGasLimit)) } return gl } @@ -255,50 +258,11 @@ func (bc *ChainManager) makeCache() { bc.cache = NewBlockCache(blockCacheLimit) } // load in last `blockCacheLimit` - 1 blocks. Last block is the current. - ancestors := bc.GetAncestors(bc.currentBlock, blockCacheLimit-1) - ancestors = append(ancestors, bc.currentBlock) - for _, block := range ancestors { + for _, block := range bc.GetBlocksFromHash(bc.currentBlock.Hash(), blockCacheLimit) { bc.cache.Push(block) } } -// Block creation & chain handling -func (bc *ChainManager) NewBlock(coinbase common.Address) *types.Block { - bc.mu.RLock() - defer bc.mu.RUnlock() - - var ( - root common.Hash - parentHash common.Hash - ) - - if bc.currentBlock != nil { - root = bc.currentBlock.Header().Root - parentHash = bc.lastBlockHash - } - - block := types.NewBlock( - parentHash, - coinbase, - root, - common.BigPow(2, 32), - 0, - nil) - block.SetUncles(nil) - block.SetTransactions(nil) - block.SetReceipts(nil) - - parent := bc.currentBlock - if parent != nil { - header := block.Header() - header.Difficulty = CalcDifficulty(block.Header(), parent.Header()) - header.Number = new(big.Int).Add(parent.Header().Number, common.Big1) - header.GasLimit = CalcGasLimit(parent) - } - - return block -} - func (bc *ChainManager) Reset() { bc.mu.Lock() defer bc.mu.Unlock() @@ -463,6 +427,19 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { } +// GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors. +func (self *ChainManager) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) { + for i := 0; i < n; i++ { + block := self.GetBlock(hash) + if block == nil { + break + } + blocks = append(blocks, block) + hash = block.ParentHash() + } + return +} + // non blocking version func (self *ChainManager) getBlockByNumber(num uint64) *types.Block { key, _ := self.blockDb.Get(append(blockNumPre, big.NewInt(int64(num)).Bytes()...)) @@ -482,19 +459,6 @@ func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncl return } -func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) { - for i := 0; i < length; i++ { - block = self.GetBlock(block.ParentHash()) - if block == nil { - break - } - - blocks = append(blocks, block) - } - - return -} - // setTotalDifficulty updates the TD of the chain manager. Note, this function // assumes that the `mu` mutex is held! func (bc *ChainManager) setTotalDifficulty(td *big.Int) { @@ -621,14 +585,12 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) { return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max) } - block.SetQueued(true) self.futureBlocks.Push(block) stats.queued++ continue } if IsParentErr(err) && self.futureBlocks.Has(block.ParentHash()) { - block.SetQueued(true) self.futureBlocks.Push(block) stats.queued++ continue diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index c56a3b3e1..afec1d0f1 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -117,7 +117,7 @@ func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) { } func loadChain(fn string, t *testing.T) (types.Blocks, error) { - fh, err := os.OpenFile(filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm) + fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm) if err != nil { return nil, err } @@ -265,7 +265,7 @@ func TestBrokenChain(t *testing.T) { } func TestChainInsertions(t *testing.T) { - t.Skip() // travil fails. + t.Skip("Skipped: outdated test files") db, _ := ethdb.NewMemDatabase() @@ -303,7 +303,7 @@ func TestChainInsertions(t *testing.T) { } func TestChainMultipleInsertions(t *testing.T) { - t.Skip() // travil fails. + t.Skip("Skipped: outdated test files") db, _ := ethdb.NewMemDatabase() @@ -346,8 +346,8 @@ func TestChainMultipleInsertions(t *testing.T) { } } -func TestGetAncestors(t *testing.T) { - t.Skip() // travil fails. +func TestGetBlocksFromHash(t *testing.T) { + t.Skip("Skipped: outdated test files") db, _ := ethdb.NewMemDatabase() chainMan := theChainManager(db, t) @@ -361,8 +361,8 @@ func TestGetAncestors(t *testing.T) { chainMan.write(block) } - ancestors := chainMan.GetAncestors(chain[len(chain)-1], 4) - fmt.Println(ancestors) + blocks := chainMan.GetBlocksFromHash(chain[len(chain)-1].Hash(), 4) + fmt.Println(blocks) } type bproc struct{} @@ -372,15 +372,17 @@ func (bproc) Process(*types.Block) (state.Logs, error) { return nil, nil } func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { var chain []*types.Block for i, difficulty := range d { - header := &types.Header{Number: big.NewInt(int64(i + 1)), Difficulty: big.NewInt(int64(difficulty))} - block := types.NewBlockWithHeader(header) - copy(block.HeaderHash[:2], []byte{byte(i + 1), seed}) + header := &types.Header{ + Coinbase: common.Address{seed}, + Number: big.NewInt(int64(i + 1)), + Difficulty: big.NewInt(int64(difficulty)), + } if i == 0 { - block.ParentHeaderHash = genesis.Hash() + header.ParentHash = genesis.Hash() } else { - copy(block.ParentHeaderHash[:2], []byte{byte(i), seed}) + header.ParentHash = chain[i-1].Hash() } - + block := types.NewBlockWithHeader(header) chain = append(chain, block) } return chain @@ -399,7 +401,6 @@ func chm(genesis *types.Block, db common.Database) *ChainManager { } func TestReorgLongest(t *testing.T) { - t.Skip("skipped while cache is removed") db, _ := ethdb.NewMemDatabase() genesis := GenesisBlock(0, db) bc := chm(genesis, db) @@ -419,7 +420,6 @@ func TestReorgLongest(t *testing.T) { } func TestReorgShortest(t *testing.T) { - t.Skip("skipped while cache is removed") db, _ := ethdb.NewMemDatabase() genesis := GenesisBlock(0, db) bc := chm(genesis, db) diff --git a/core/genesis.go b/core/genesis.go index dd894e0b0..de2eee9db 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -11,38 +11,18 @@ import ( "github.com/ethereum/go-ethereum/params" ) -/* - * This is the special genesis block. - */ - -var ZeroHash256 = make([]byte, 32) -var ZeroHash160 = make([]byte, 20) -var ZeroHash512 = make([]byte, 64) - +// GenesisBlock creates a genesis block with the given nonce. func GenesisBlock(nonce uint64, db common.Database) *types.Block { - genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, params.GenesisDifficulty, nonce, nil) - genesis.Header().Number = common.Big0 - genesis.Header().GasLimit = params.GenesisGasLimit - genesis.Header().GasUsed = common.Big0 - genesis.Header().Time = 0 - - genesis.Td = common.Big0 - - genesis.SetUncles([]*types.Header{}) - genesis.SetTransactions(types.Transactions{}) - genesis.SetReceipts(types.Receipts{}) - var accounts map[string]struct { Balance string Code string } err := json.Unmarshal(GenesisAccounts, &accounts) if err != nil { - fmt.Println("enable to decode genesis json data:", err) + fmt.Println("unable to decode genesis json data:", err) os.Exit(1) } - - statedb := state.New(genesis.Root(), db) + statedb := state.New(common.Hash{}, db) for addr, account := range accounts { codedAddr := common.Hex2Bytes(addr) accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr)) @@ -51,10 +31,15 @@ func GenesisBlock(nonce uint64, db common.Database) *types.Block { statedb.UpdateStateObject(accountState) } statedb.Sync() - genesis.Header().Root = statedb.Root() - genesis.Td = params.GenesisDifficulty - return genesis + block := types.NewBlock(&types.Header{ + Difficulty: params.GenesisDifficulty, + GasLimit: params.GenesisGasLimit, + Nonce: types.EncodeNonce(nonce), + Root: statedb.Root(), + }, nil, nil, nil) + block.Td = params.GenesisDifficulty + return block } var GenesisAccounts = []byte(`{ diff --git a/core/state_transition.go b/core/state_transition.go index 915dd466b..2c8770cbe 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -73,16 +73,17 @@ func MessageGasValue(msg Message) *big.Int { return new(big.Int).Mul(msg.Gas(), msg.GasPrice()) } -func IntrinsicGas(msg Message) *big.Int { +// IntrinsicGas computes the 'intrisic gas' for a message +// with the given data. +func IntrinsicGas(data []byte) *big.Int { igas := new(big.Int).Set(params.TxGas) - for _, byt := range msg.Data() { + for _, byt := range data { if byt != 0 { igas.Add(igas, params.TxDataNonZeroGas) } else { igas.Add(igas, params.TxDataZeroGas) } } - return igas } @@ -195,7 +196,7 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er sender, _ := self.From() // err checked in preCheck // Pay intrinsic gas - if err = self.UseGas(IntrinsicGas(self.msg)); err != nil { + if err = self.UseGas(IntrinsicGas(self.msg.Data())); err != nil { return nil, nil, InvalidTxError(err) } diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 45db04eef..bf28647c3 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -180,7 +180,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { } // Should supply enough intrinsic gas - if tx.Gas().Cmp(IntrinsicGas(tx)) < 0 { + if tx.Gas().Cmp(IntrinsicGas(tx.Data())) < 0 { return ErrIntrinsicGas } diff --git a/core/types/block.go b/core/types/block.go index d7963981e..31ea478d4 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -15,71 +15,59 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -type Header struct { - // Hash to the previous block - ParentHash common.Hash - // Uncles of this block - UncleHash common.Hash - // The coin base address - Coinbase common.Address - // Block Trie state - Root common.Hash - // Tx sha - TxHash common.Hash - // Receipt sha - ReceiptHash common.Hash - // Bloom - Bloom Bloom - // Difficulty for the current block - Difficulty *big.Int - // The block number - Number *big.Int - // Gas limit - GasLimit *big.Int - // Gas used - GasUsed *big.Int - // Creation time - Time uint64 - // Extra data - Extra []byte - // Mix digest for quick checking to prevent DOS - MixDigest common.Hash - // Nonce - Nonce [8]byte -} +// A BlockNonce is a 64-bit hash which proves (combined with the +// mix-hash) that a suffcient amount of computation has been carried +// out on a block. +type BlockNonce [8]byte -func (self *Header) Hash() common.Hash { - return rlpHash(self.rlpData(true)) +func EncodeNonce(i uint64) BlockNonce { + var n BlockNonce + binary.BigEndian.PutUint64(n[:], i) + return n } -func (self *Header) HashNoNonce() common.Hash { - return rlpHash(self.rlpData(false)) +func (n BlockNonce) Uint64() uint64 { + return binary.BigEndian.Uint64(n[:]) } -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, - } - if withNonce { - fields = append(fields, self.MixDigest, self.Nonce) - } - return fields -} - -func (self *Header) RlpData() interface{} { - return self.rlpData(true) +type Header struct { + ParentHash common.Hash // Hash to the previous block + UncleHash common.Hash // Uncles of this block + Coinbase common.Address // The coin base address + Root common.Hash // Block Trie state + TxHash common.Hash // Tx sha + ReceiptHash common.Hash // Receipt sha + Bloom Bloom // Bloom + Difficulty *big.Int // Difficulty for the current block + Number *big.Int // The block number + GasLimit *big.Int // Gas limit + GasUsed *big.Int // Gas used + Time uint64 // Creation time + Extra []byte // Extra data + MixDigest common.Hash // for quick difficulty verification + Nonce BlockNonce +} + +func (h *Header) Hash() common.Hash { + return rlpHash(h) +} + +func (h *Header) HashNoNonce() common.Hash { + return rlpHash([]interface{}{ + h.ParentHash, + h.UncleHash, + h.Coinbase, + h.Root, + h.TxHash, + h.ReceiptHash, + h.Bloom, + h.Difficulty, + h.Number, + h.GasLimit, + h.GasUsed, + h.Time, + h.Extra, + }) } func (h *Header) UnmarshalJSON(data []byte) error { @@ -112,20 +100,14 @@ func rlpHash(x interface{}) (h common.Hash) { } type Block struct { - // Preset Hash for mock (Tests) - HeaderHash common.Hash - ParentHeaderHash common.Hash - // ^^^^ ignore ^^^^ - header *Header uncles []*Header transactions Transactions - Td *big.Int - queued bool // flag for blockpool to skip TD check + receipts Receipts + Td *big.Int + queued bool // flag for blockpool to skip TD check ReceivedAt time.Time - - receipts Receipts } // StorageBlock defines the RLP encoding of a Block stored in the @@ -148,43 +130,90 @@ type storageblock struct { TD *big.Int } -func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra []byte) *Block { - header := &Header{ - Root: root, - ParentHash: parentHash, - Coinbase: coinbase, - Difficulty: difficulty, - Time: uint64(time.Now().Unix()), - Extra: extra, - GasUsed: new(big.Int), - GasLimit: new(big.Int), - Number: new(big.Int), +var ( + emptyRootHash = DeriveSha(Transactions{}) + emptyUncleHash = CalcUncleHash(nil) +) + +// NewBlock creates a new block. The input data is copied, +// changes to header and to the field values will not affect the +// block. +// +// The values of TxHash, UncleHash, ReceiptHash and Bloom in header +// are ignored and set to values derived from the given txs, uncles +// and receipts. +func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block { + b := &Block{header: copyHeader(header), Td: new(big.Int)} + + // TODO: panic if len(txs) != len(receipts) + if len(txs) == 0 { + b.header.TxHash = emptyRootHash + } else { + b.header.TxHash = DeriveSha(Transactions(txs)) + b.transactions = make(Transactions, len(txs)) + copy(b.transactions, txs) } - header.SetNonce(nonce) - block := &Block{header: header} - block.Td = new(big.Int) - return block -} + if len(receipts) == 0 { + b.header.ReceiptHash = emptyRootHash + } else { + b.header.ReceiptHash = DeriveSha(Receipts(receipts)) + b.header.Bloom = CreateBloom(receipts) + b.receipts = make([]*Receipt, len(receipts)) + copy(b.receipts, receipts) + } -func (self *Header) SetNonce(nonce uint64) { - binary.BigEndian.PutUint64(self.Nonce[:], nonce) + if len(uncles) == 0 { + b.header.UncleHash = emptyUncleHash + } else { + b.header.UncleHash = CalcUncleHash(uncles) + b.uncles = make([]*Header, len(uncles)) + for i := range uncles { + b.uncles[i] = copyHeader(uncles[i]) + } + } + + return b } +// NewBlockWithHeader creates a block with the given header data. The +// header data is copied, changes to header and to the field values +// will not affect the block. func NewBlockWithHeader(header *Header) *Block { - return &Block{header: header} + return &Block{header: copyHeader(header)} +} + +func copyHeader(h *Header) *Header { + cpy := *h + if cpy.Difficulty = new(big.Int); h.Difficulty != nil { + cpy.Difficulty.Set(h.Difficulty) + } + if cpy.Number = new(big.Int); h.Number != nil { + cpy.Number.Set(h.Number) + } + if cpy.GasLimit = new(big.Int); h.GasLimit != nil { + cpy.GasLimit.Set(h.GasLimit) + } + if cpy.GasUsed = new(big.Int); h.GasUsed != nil { + cpy.GasUsed.Set(h.GasUsed) + } + if len(h.Extra) > 0 { + cpy.Extra = make([]byte, len(h.Extra)) + copy(cpy.Extra, h.Extra) + } + return &cpy } -func (self *Block) ValidateFields() error { - if self.header == nil { +func (b *Block) ValidateFields() error { + if b.header == nil { return fmt.Errorf("header is nil") } - for i, transaction := range self.transactions { + for i, transaction := range b.transactions { if transaction == nil { return fmt.Errorf("transaction %d is nil", i) } } - for i, uncle := range self.uncles { + for i, uncle := range b.uncles { if uncle == nil { return fmt.Errorf("uncle %d is nil", i) } @@ -192,64 +221,48 @@ func (self *Block) ValidateFields() error { return nil } -func (self *Block) DecodeRLP(s *rlp.Stream) error { +func (b *Block) DecodeRLP(s *rlp.Stream) error { var eb extblock if err := s.Decode(&eb); err != nil { return err } - self.header, self.uncles, self.transactions = eb.Header, eb.Uncles, eb.Txs + b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs return nil } -func (self Block) EncodeRLP(w io.Writer) error { +func (b Block) EncodeRLP(w io.Writer) error { return rlp.Encode(w, extblock{ - Header: self.header, - Txs: self.transactions, - Uncles: self.uncles, + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, }) } -func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error { +func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error { var sb storageblock if err := s.Decode(&sb); err != nil { return err } - self.header, self.uncles, self.transactions, self.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD + b.header, b.uncles, b.transactions, b.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD return nil } -func (self StorageBlock) EncodeRLP(w io.Writer) error { +func (b StorageBlock) EncodeRLP(w io.Writer) error { return rlp.Encode(w, storageblock{ - Header: self.header, - Txs: self.transactions, - Uncles: self.uncles, - TD: self.Td, + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, + TD: b.Td, }) } -func (self *Block) Header() *Header { - return self.header -} - -func (self *Block) Uncles() []*Header { - return self.uncles -} - -func (self *Block) CalculateUnclesHash() common.Hash { - return rlpHash(self.uncles) -} +// TODO: copies +func (b *Block) Uncles() []*Header { return b.uncles } +func (b *Block) Transactions() Transactions { return b.transactions } +func (b *Block) Receipts() Receipts { return b.receipts } -func (self *Block) SetUncles(uncleHeaders []*Header) { - self.uncles = uncleHeaders - self.header.UncleHash = rlpHash(uncleHeaders) -} - -func (self *Block) Transactions() Transactions { - return self.transactions -} - -func (self *Block) Transaction(hash common.Hash) *Transaction { - for _, transaction := range self.transactions { +func (b *Block) Transaction(hash common.Hash) *Transaction { + for _, transaction := range b.transactions { if transaction.Hash() == hash { return transaction } @@ -257,74 +270,33 @@ func (self *Block) Transaction(hash common.Hash) *Transaction { return nil } -func (self *Block) SetTransactions(transactions Transactions) { - self.transactions = transactions - self.header.TxHash = DeriveSha(transactions) -} -func (self *Block) AddTransaction(transaction *Transaction) { - self.transactions = append(self.transactions, transaction) - self.SetTransactions(self.transactions) -} - -func (self *Block) Receipts() Receipts { - return self.receipts -} - -func (self *Block) SetReceipts(receipts Receipts) { - self.receipts = receipts - self.header.ReceiptHash = DeriveSha(receipts) - self.header.Bloom = CreateBloom(receipts) -} -func (self *Block) AddReceipt(receipt *Receipt) { - self.receipts = append(self.receipts, receipt) - self.SetReceipts(self.receipts) -} - -func (self *Block) RlpData() interface{} { - return []interface{}{self.header, self.transactions, self.uncles} -} +func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) } +func (b *Block) GasLimit() *big.Int { return new(big.Int).Set(b.header.GasLimit) } +func (b *Block) GasUsed() *big.Int { return new(big.Int).Set(b.header.GasUsed) } +func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) } -func (self *Block) RlpDataForStorage() interface{} { - return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */} -} +func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() } +func (b *Block) MixDigest() common.Hash { return b.header.MixDigest } +func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) } +func (b *Block) Bloom() Bloom { return b.header.Bloom } +func (b *Block) Coinbase() common.Address { return b.header.Coinbase } +func (b *Block) Time() int64 { return int64(b.header.Time) } +func (b *Block) Root() common.Hash { return b.header.Root } +func (b *Block) ParentHash() common.Hash { return b.header.ParentHash } +func (b *Block) TxHash() common.Hash { return b.header.TxHash } +func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } +func (b *Block) UncleHash() common.Hash { return b.header.UncleHash } +func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } -// 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) MixDigest() common.Hash { return self.header.MixDigest } -func (self *Block) Nonce() uint64 { - return binary.BigEndian.Uint64(self.header.Nonce[:]) -} -func (self *Block) SetNonce(nonce uint64) { - self.header.SetNonce(nonce) -} +func (b *Block) Header() *Header { return copyHeader(b.header) } -func (self *Block) Queued() bool { return self.queued } -func (self *Block) SetQueued(q bool) { self.queued = q } - -func (self *Block) Bloom() Bloom { return self.header.Bloom } -func (self *Block) Coinbase() common.Address { return self.header.Coinbase } -func (self *Block) Time() int64 { return int64(self.header.Time) } -func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } -func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } -func (self *Block) Root() common.Hash { return self.header.Root } -func (self *Block) SetRoot(root common.Hash) { self.header.Root = root } -func (self *Block) GetTransaction(i int) *Transaction { - if len(self.transactions) > i { - return self.transactions[i] - } - return nil -} -func (self *Block) GetUncle(i int) *Header { - if len(self.uncles) > i { - return self.uncles[i] - } - return nil +func (b *Block) HashNoNonce() common.Hash { + return b.header.HashNoNonce() } -func (self *Block) Size() common.StorageSize { +func (b *Block) Size() common.StorageSize { c := writeCounter(0) - rlp.Encode(&c, self) + rlp.Encode(&c, b) return common.StorageSize(c) } @@ -335,48 +307,32 @@ func (c *writeCounter) Write(b []byte) (int, error) { return len(b), nil } -// Implement pow.Block -func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } -func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() } - -func (self *Block) Hash() common.Hash { - if (self.HeaderHash != common.Hash{}) { - return self.HeaderHash - } else { - return self.header.Hash() - } +func CalcUncleHash(uncles []*Header) common.Hash { + return rlpHash(uncles) } -func (self *Block) ParentHash() common.Hash { - if (self.ParentHeaderHash != common.Hash{}) { - return self.ParentHeaderHash - } else { - return self.header.ParentHash +// WithMiningResult returns a new block with the data from b +// where nonce and mix digest are set to the provided values. +func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block { + cpy := *b.header + binary.BigEndian.PutUint64(cpy.Nonce[:], nonce) + cpy.MixDigest = mixDigest + return &Block{ + header: &cpy, + transactions: b.transactions, + receipts: b.receipts, + uncles: b.uncles, + Td: b.Td, } } -func (self *Block) Copy() *Block { - block := NewBlock(self.header.ParentHash, self.Coinbase(), self.Root(), new(big.Int), self.Nonce(), self.header.Extra) - block.header.Bloom = self.header.Bloom - block.header.TxHash = self.header.TxHash - block.transactions = self.transactions - block.header.UncleHash = self.header.UncleHash - block.uncles = self.uncles - block.header.GasLimit.Set(self.header.GasLimit) - block.header.GasUsed.Set(self.header.GasUsed) - block.header.ReceiptHash = self.header.ReceiptHash - block.header.Difficulty.Set(self.header.Difficulty) - block.header.Number.Set(self.header.Number) - block.header.Time = self.header.Time - block.header.MixDigest = self.header.MixDigest - if self.Td != nil { - block.Td.Set(self.Td) - } +// Implement pow.Block - return block +func (b *Block) Hash() common.Hash { + return b.header.Hash() } -func (self *Block) String() string { +func (b *Block) String() string { str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v { MinerHash: %x %v @@ -385,20 +341,11 @@ Transactions: Uncles: %v } -`, self.Number(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles) - - if (self.HeaderHash != common.Hash{}) { - str += fmt.Sprintf("\nFake hash = %x", self.HeaderHash) - } - - if (self.ParentHeaderHash != common.Hash{}) { - str += fmt.Sprintf("\nFake parent hash = %x", self.ParentHeaderHash) - } - +`, b.Number(), b.Size(), b.Td, b.header.HashNoNonce(), b.header, b.transactions, b.uncles) return str } -func (self *Header) String() string { +func (h *Header) String() string { return fmt.Sprintf(`Header(%x): [ ParentHash: %x @@ -414,9 +361,9 @@ func (self *Header) String() string { GasUsed: %v Time: %v Extra: %s - MixDigest: %x + MixDigest: %x Nonce: %x -]`, self.Hash(), 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.MixDigest, self.Nonce) +]`, h.Hash(), h.ParentHash, h.UncleHash, h.Coinbase, h.Root, h.TxHash, h.ReceiptHash, h.Bloom, h.Difficulty, h.Number, h.GasLimit, h.GasUsed, h.Time, h.Extra, h.MixDigest, h.Nonce) } type Blocks []*Block @@ -442,4 +389,4 @@ func (self blockSorter) Swap(i, j int) { } func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } -func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 } +func Number(b1, b2 *Block) bool { return b1.header.Number.Cmp(b2.header.Number) < 0 } diff --git a/core/vm_env.go b/core/vm_env.go index da862d5c8..6dd83acde 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -10,32 +10,32 @@ import ( ) type VMEnv struct { - state *state.StateDB - block *types.Block - msg Message - depth int - chain *ChainManager - typ vm.Type + state *state.StateDB + header *types.Header + msg Message + depth int + chain *ChainManager + typ vm.Type // structured logging logs []vm.StructLog } -func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv { +func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, header *types.Header) *VMEnv { return &VMEnv{ - chain: chain, - state: state, - block: block, - msg: msg, - typ: vm.StdVmTy, + chain: chain, + state: state, + header: header, + msg: msg, + typ: vm.StdVmTy, } } func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } -func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } -func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() } -func (self *VMEnv) Time() int64 { return self.block.Time() } -func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } -func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } +func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } +func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } +func (self *VMEnv) Time() int64 { return int64(self.header.Time) } +func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty } +func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit } func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) Depth() int { return self.depth } |