core/types: make blocks immutable
This commit is contained in:
parent
654564e164
commit
1d42888d30
@ -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) {
|
||||
|
@ -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[:]...))
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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{}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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})
|
||||
if i == 0 {
|
||||
block.ParentHeaderHash = genesis.Hash()
|
||||
} else {
|
||||
copy(block.ParentHeaderHash[:2], []byte{byte(i), seed})
|
||||
header := &types.Header{
|
||||
Coinbase: common.Address{seed},
|
||||
Number: big.NewInt(int64(i + 1)),
|
||||
Difficulty: big.NewInt(int64(difficulty)),
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
header.ParentHash = genesis.Hash()
|
||||
} else {
|
||||
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)
|
||||
|
@ -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(`{
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -15,71 +15,59 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// 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 EncodeNonce(i uint64) BlockNonce {
|
||||
var n BlockNonce
|
||||
binary.BigEndian.PutUint64(n[:], i)
|
||||
return n
|
||||
}
|
||||
|
||||
func (n BlockNonce) Uint64() uint64 {
|
||||
return binary.BigEndian.Uint64(n[:])
|
||||
}
|
||||
|
||||
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
|
||||
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 (self *Header) Hash() common.Hash {
|
||||
return rlpHash(self.rlpData(true))
|
||||
func (h *Header) Hash() common.Hash {
|
||||
return rlpHash(h)
|
||||
}
|
||||
|
||||
func (self *Header) HashNoNonce() common.Hash {
|
||||
return rlpHash(self.rlpData(false))
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
func (self *Header) SetNonce(nonce uint64) {
|
||||
binary.BigEndian.PutUint64(self.Nonce[:], nonce)
|
||||
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)
|
||||
}
|
||||
|
||||
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 (self *Block) ValidateFields() error {
|
||||
if self.header == nil {
|
||||
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 (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
|
||||
}
|
||||
// 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) Uncles() []*Header {
|
||||
return self.uncles
|
||||
}
|
||||
|
||||
func (self *Block) CalculateUnclesHash() common.Hash {
|
||||
return rlpHash(self.uncles)
|
||||
}
|
||||
|
||||
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 (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 (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) }
|
||||
|
||||
func (b *Block) Header() *Header { return copyHeader(b.header) }
|
||||
|
||||
func (b *Block) HashNoNonce() common.Hash {
|
||||
return b.header.HashNoNonce()
|
||||
}
|
||||
|
||||
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 (self *Block) RlpDataForStorage() interface{} {
|
||||
return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */}
|
||||
}
|
||||
|
||||
// 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 (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 (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
|
||||
}
|
||||
|
||||
func CalcUncleHash(uncles []*Header) common.Hash {
|
||||
return rlpHash(uncles)
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (b *Block) Hash() common.Hash {
|
||||
return b.header.Hash()
|
||||
}
|
||||
|
||||
func (self *Block) ParentHash() common.Hash {
|
||||
if (self.ParentHeaderHash != common.Hash{}) {
|
||||
return self.ParentHeaderHash
|
||||
} else {
|
||||
return self.header.ParentHash
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
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 }
|
||||
|
@ -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 }
|
||||
|
@ -40,7 +40,10 @@ func createHashes(amount int, root common.Hash) (hashes []common.Hash) {
|
||||
|
||||
// createBlock assembles a new block at the given chain height.
|
||||
func createBlock(i int, parent, hash common.Hash) *types.Block {
|
||||
header := &types.Header{Number: big.NewInt(int64(i))}
|
||||
header := &types.Header{
|
||||
Hash: hash,
|
||||
Number: big.NewInt(int64(i))
|
||||
}
|
||||
block := types.NewBlockWithHeader(header)
|
||||
block.HeaderHash = hash
|
||||
block.ParentHeaderHash = parent
|
||||
|
@ -90,15 +90,13 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
func (self *CpuAgent) mine(block *types.Block, stop <- chan struct{}) {
|
||||
func (self *CpuAgent) mine(block *types.Block, stop <-chan struct{}) {
|
||||
glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
|
||||
|
||||
// Mine
|
||||
nonce, mixDigest := self.pow.Search(block, stop)
|
||||
if nonce != 0 {
|
||||
block.SetNonce(nonce)
|
||||
block.Header().MixDigest = common.BytesToHash(mixDigest)
|
||||
self.returnCh <- block
|
||||
self.returnCh <- block.WithMiningResult(nonce, common.BytesToHash(mixDigest))
|
||||
} else {
|
||||
self.returnCh <- nil
|
||||
}
|
||||
|
@ -81,9 +81,7 @@ func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, seedHash common.Hash)
|
||||
|
||||
// Make sure the external miner was working on the right hash
|
||||
if a.currentWork != nil && a.work != nil {
|
||||
a.currentWork.SetNonce(nonce)
|
||||
a.currentWork.Header().MixDigest = mixDigest
|
||||
a.returnCh <- a.currentWork
|
||||
a.returnCh <- a.currentWork.WithMiningResult(nonce, mixDigest)
|
||||
//a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()}
|
||||
return true
|
||||
}
|
||||
|
186
miner/worker.go
186
miner/worker.go
@ -49,10 +49,8 @@ type uint64RingBuffer struct {
|
||||
// environment is the workers current environment and holds
|
||||
// all of the current state information
|
||||
type environment struct {
|
||||
totalUsedGas *big.Int // total gas usage in the cycle
|
||||
state *state.StateDB // apply state changes here
|
||||
coinbase *state.StateObject // the miner's account
|
||||
block *types.Block // the new block
|
||||
ancestors *set.Set // ancestor set (used for checking uncle parent validity)
|
||||
family *set.Set // family set (used for checking uncle invalidity)
|
||||
uncles *set.Set // uncle set
|
||||
@ -63,22 +61,12 @@ type environment struct {
|
||||
ownedAccounts *set.Set
|
||||
lowGasTxs types.Transactions
|
||||
localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion)
|
||||
}
|
||||
|
||||
// env returns a new environment for the current cycle
|
||||
func env(block *types.Block, eth core.Backend) *environment {
|
||||
state := state.New(block.Root(), eth.StateDb())
|
||||
env := &environment{
|
||||
totalUsedGas: new(big.Int),
|
||||
state: state,
|
||||
block: block,
|
||||
ancestors: set.New(),
|
||||
family: set.New(),
|
||||
uncles: set.New(),
|
||||
coinbase: state.GetOrNewStateObject(block.Coinbase()),
|
||||
}
|
||||
block *types.Block // the new block
|
||||
|
||||
return env
|
||||
header *types.Header
|
||||
txs []*types.Transaction
|
||||
receipts []*types.Receipt
|
||||
}
|
||||
|
||||
// worker is the main object which takes care of applying messages to the new state
|
||||
@ -137,14 +125,20 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker {
|
||||
func (self *worker) pendingState() *state.StateDB {
|
||||
self.currentMu.Lock()
|
||||
defer self.currentMu.Unlock()
|
||||
|
||||
return self.current.state
|
||||
}
|
||||
|
||||
func (self *worker) pendingBlock() *types.Block {
|
||||
self.currentMu.Lock()
|
||||
defer self.currentMu.Unlock()
|
||||
|
||||
if atomic.LoadInt32(&self.mining) == 0 {
|
||||
return types.NewBlock(
|
||||
self.current.header,
|
||||
self.current.txs,
|
||||
nil,
|
||||
self.current.receipts,
|
||||
)
|
||||
}
|
||||
return self.current.block
|
||||
}
|
||||
|
||||
@ -206,7 +200,7 @@ out:
|
||||
// Apply transaction to the pending state if we're not mining
|
||||
if atomic.LoadInt32(&self.mining) == 0 {
|
||||
self.mu.Lock()
|
||||
self.commitTransactions(types.Transactions{ev.Tx})
|
||||
self.current.commitTransactions(types.Transactions{ev.Tx}, self.gasPrice, self.proc)
|
||||
self.mu.Unlock()
|
||||
}
|
||||
}
|
||||
@ -259,8 +253,8 @@ func (self *worker) wait() {
|
||||
jsonlogger.LogJson(&logger.EthMinerNewBlock{
|
||||
BlockHash: block.Hash().Hex(),
|
||||
BlockNumber: block.Number(),
|
||||
ChainHeadHash: block.ParentHeaderHash.Hex(),
|
||||
BlockPrevHash: block.ParentHeaderHash.Hex(),
|
||||
ChainHeadHash: block.ParentHash().Hex(),
|
||||
BlockPrevHash: block.ParentHash().Hex(),
|
||||
})
|
||||
} else {
|
||||
self.commitNewWork()
|
||||
@ -271,14 +265,12 @@ func (self *worker) wait() {
|
||||
|
||||
func (self *worker) push() {
|
||||
if atomic.LoadInt32(&self.mining) == 1 {
|
||||
self.current.block.SetRoot(self.current.state.Root())
|
||||
|
||||
// push new work to agents
|
||||
for _, agent := range self.agents {
|
||||
atomic.AddInt32(&self.atWork, 1)
|
||||
|
||||
if agent.Work() != nil {
|
||||
agent.Work() <- self.current.block.Copy()
|
||||
agent.Work() <- self.current.block
|
||||
} else {
|
||||
common.Report(fmt.Sprintf("%v %T\n", agent, agent))
|
||||
}
|
||||
@ -286,22 +278,20 @@ func (self *worker) push() {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *worker) makeCurrent() {
|
||||
block := self.chain.NewBlock(self.coinbase)
|
||||
parent := self.chain.GetBlock(block.ParentHash())
|
||||
// TMP fix for build server ...
|
||||
if parent == nil {
|
||||
return
|
||||
// makeCurrent creates a new environment for the current cycle.
|
||||
func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
|
||||
state := state.New(parent.Root(), self.eth.StateDb())
|
||||
current := &environment{
|
||||
state: state,
|
||||
ancestors: set.New(),
|
||||
family: set.New(),
|
||||
uncles: set.New(),
|
||||
header: header,
|
||||
coinbase: state.GetOrNewStateObject(self.coinbase),
|
||||
}
|
||||
|
||||
if block.Time() <= parent.Time() {
|
||||
block.Header().Time = parent.Header().Time + 1
|
||||
}
|
||||
block.Header().Extra = self.extra
|
||||
|
||||
// when 08 is processed ancestors contain 07 (quick block)
|
||||
current := env(block, self.eth)
|
||||
for _, ancestor := range self.chain.GetAncestors(block, 7) {
|
||||
for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
||||
for _, uncle := range ancestor.Uncles() {
|
||||
current.family.Add(uncle.Hash())
|
||||
}
|
||||
@ -309,6 +299,7 @@ func (self *worker) makeCurrent() {
|
||||
current.ancestors.Add(ancestor.Hash())
|
||||
}
|
||||
accounts, _ := self.eth.AccountManager().Accounts()
|
||||
|
||||
// Keep track of transactions which return errors so they can be removed
|
||||
current.remove = set.New()
|
||||
current.tcount = 0
|
||||
@ -318,9 +309,6 @@ func (self *worker) makeCurrent() {
|
||||
if self.current != nil {
|
||||
current.localMinedBlocks = self.current.localMinedBlocks
|
||||
}
|
||||
|
||||
current.coinbase.SetGasLimit(core.CalcGasLimit(parent))
|
||||
|
||||
self.current = current
|
||||
}
|
||||
|
||||
@ -352,13 +340,13 @@ func (self *worker) isBlockLocallyMined(deepBlockNum uint64) bool {
|
||||
|
||||
//Does the block at {deepBlockNum} send earnings to my coinbase?
|
||||
var block = self.chain.GetBlockByNumber(deepBlockNum)
|
||||
return block != nil && block.Header().Coinbase == self.coinbase
|
||||
return block != nil && block.Coinbase() == self.coinbase
|
||||
}
|
||||
|
||||
func (self *worker) logLocalMinedBlocks(previous *environment) {
|
||||
if previous != nil && self.current.localMinedBlocks != nil {
|
||||
nextBlockNum := self.current.block.Number().Uint64()
|
||||
for checkBlockNum := previous.block.Number().Uint64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
|
||||
nextBlockNum := self.current.block.NumberU64()
|
||||
for checkBlockNum := previous.block.NumberU64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
|
||||
inspectBlockNum := checkBlockNum - miningLogAtDepth
|
||||
if self.isBlockLocallyMined(inspectBlockNum) {
|
||||
glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum)
|
||||
@ -376,18 +364,35 @@ func (self *worker) commitNewWork() {
|
||||
defer self.currentMu.Unlock()
|
||||
|
||||
tstart := time.Now()
|
||||
parent := self.chain.CurrentBlock()
|
||||
tstamp := tstart.Unix()
|
||||
if tstamp <= parent.Time() {
|
||||
tstamp = parent.Time() + 1
|
||||
}
|
||||
num := parent.Number()
|
||||
header := &types.Header{
|
||||
ParentHash: parent.Hash(),
|
||||
Number: num.Add(num, common.Big1),
|
||||
Difficulty: core.CalcDifficulty(tstamp, parent.Time(), parent.Difficulty()),
|
||||
GasLimit: core.CalcGasLimit(parent),
|
||||
GasUsed: new(big.Int),
|
||||
Coinbase: self.coinbase,
|
||||
Extra: self.extra,
|
||||
Time: uint64(tstamp),
|
||||
}
|
||||
|
||||
previous := self.current
|
||||
self.makeCurrent()
|
||||
self.makeCurrent(parent, header)
|
||||
current := self.current
|
||||
|
||||
// commit transactions for this run.
|
||||
transactions := self.eth.TxPool().GetTransactions()
|
||||
sort.Sort(types.TxByNonce{transactions})
|
||||
|
||||
// commit transactions for this run
|
||||
self.commitTransactions(transactions)
|
||||
current.coinbase.SetGasLimit(header.GasLimit)
|
||||
current.commitTransactions(transactions, self.gasPrice, self.proc)
|
||||
self.eth.TxPool().RemoveTransactions(current.lowGasTxs)
|
||||
|
||||
// compute uncles for the new block.
|
||||
var (
|
||||
uncles []*types.Header
|
||||
badUncles []common.Hash
|
||||
@ -396,88 +401,76 @@ func (self *worker) commitNewWork() {
|
||||
if len(uncles) == 2 {
|
||||
break
|
||||
}
|
||||
|
||||
if err := self.commitUncle(uncle.Header()); err != nil {
|
||||
if glog.V(logger.Ridiculousness) {
|
||||
glog.V(logger.Detail).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
|
||||
glog.V(logger.Detail).Infoln(uncle)
|
||||
}
|
||||
|
||||
badUncles = append(badUncles, hash)
|
||||
} else {
|
||||
glog.V(logger.Debug).Infof("commiting %x as uncle\n", hash[:4])
|
||||
uncles = append(uncles, uncle.Header())
|
||||
}
|
||||
}
|
||||
for _, hash := range badUncles {
|
||||
delete(self.possibleUncles, hash)
|
||||
}
|
||||
|
||||
// We only care about logging if we're actually mining
|
||||
// commit state root after all state transitions.
|
||||
core.AccumulateRewards(self.current.state, header, uncles)
|
||||
current.state.Update()
|
||||
header.Root = current.state.Root()
|
||||
|
||||
// create the new block whose nonce will be mined.
|
||||
current.block = types.NewBlock(header, current.txs, uncles, current.receipts)
|
||||
|
||||
// We only care about logging if we're actually mining.
|
||||
if atomic.LoadInt32(&self.mining) == 1 {
|
||||
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", current.block.Number(), current.tcount, len(uncles), time.Since(tstart))
|
||||
self.logLocalMinedBlocks(previous)
|
||||
}
|
||||
|
||||
for _, hash := range badUncles {
|
||||
delete(self.possibleUncles, hash)
|
||||
}
|
||||
|
||||
self.current.block.SetUncles(uncles)
|
||||
|
||||
core.AccumulateRewards(self.current.state, self.current.block)
|
||||
|
||||
self.current.state.Update()
|
||||
|
||||
self.push()
|
||||
}
|
||||
|
||||
var (
|
||||
inclusionReward = new(big.Int).Div(core.BlockReward, big.NewInt(32))
|
||||
_uncleReward = new(big.Int).Mul(core.BlockReward, big.NewInt(15))
|
||||
uncleReward = new(big.Int).Div(_uncleReward, big.NewInt(16))
|
||||
)
|
||||
|
||||
func (self *worker) commitUncle(uncle *types.Header) error {
|
||||
if self.current.uncles.Has(uncle.Hash()) {
|
||||
// Error not unique
|
||||
hash := uncle.Hash()
|
||||
if self.current.uncles.Has(hash) {
|
||||
return core.UncleError("Uncle not unique")
|
||||
}
|
||||
|
||||
if !self.current.ancestors.Has(uncle.ParentHash) {
|
||||
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||
}
|
||||
|
||||
if self.current.family.Has(uncle.Hash()) {
|
||||
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", uncle.Hash()))
|
||||
if self.current.family.Has(hash) {
|
||||
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash))
|
||||
}
|
||||
self.current.uncles.Add(uncle.Hash())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *worker) commitTransactions(transactions types.Transactions) {
|
||||
current := self.current
|
||||
|
||||
func (env *environment) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
|
||||
for _, tx := range transactions {
|
||||
// We can skip err. It has already been validated in the tx pool
|
||||
from, _ := tx.From()
|
||||
|
||||
// Check if it falls within margin. Txs from owned accounts are always processed.
|
||||
if tx.GasPrice().Cmp(self.gasPrice) < 0 && !current.ownedAccounts.Has(from) {
|
||||
if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
|
||||
// ignore the transaction and transactor. We ignore the transactor
|
||||
// because nonce will fail after ignoring this transaction so there's
|
||||
// no point
|
||||
current.lowGasTransactors.Add(from)
|
||||
env.lowGasTransactors.Add(from)
|
||||
|
||||
glog.V(logger.Info).Infof("transaction(%x) below gas price (tx=%v ask=%v). All sequential txs from this address(%x) will be ignored\n", tx.Hash().Bytes()[:4], common.CurrencyToString(tx.GasPrice()), common.CurrencyToString(self.gasPrice), from[:4])
|
||||
glog.V(logger.Info).Infof("transaction(%x) below gas price (tx=%v ask=%v). All sequential txs from this address(%x) will be ignored\n", tx.Hash().Bytes()[:4], common.CurrencyToString(tx.GasPrice()), common.CurrencyToString(gasPrice), from[:4])
|
||||
}
|
||||
|
||||
// Continue with the next transaction if the transaction sender is included in
|
||||
// the low gas tx set. This will also remove the tx and all sequential transaction
|
||||
// from this transactor
|
||||
if current.lowGasTransactors.Has(from) {
|
||||
if env.lowGasTransactors.Has(from) {
|
||||
// add tx to the low gas set. This will be removed at the end of the run
|
||||
// owned accounts are ignored
|
||||
if !current.ownedAccounts.Has(from) {
|
||||
current.lowGasTxs = append(current.lowGasTxs, tx)
|
||||
if !env.ownedAccounts.Has(from) {
|
||||
env.lowGasTxs = append(env.lowGasTxs, tx)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -487,46 +480,41 @@ func (self *worker) commitTransactions(transactions types.Transactions) {
|
||||
// the transaction is processed (that could potentially be included in the block) it
|
||||
// will throw a nonce error because the previous transaction hasn't been processed.
|
||||
// Therefor we need to ignore any transaction after the ignored one.
|
||||
if current.ignoredTransactors.Has(from) {
|
||||
if env.ignoredTransactors.Has(from) {
|
||||
continue
|
||||
}
|
||||
|
||||
self.current.state.StartRecord(tx.Hash(), common.Hash{}, 0)
|
||||
env.state.StartRecord(tx.Hash(), common.Hash{}, 0)
|
||||
|
||||
err := self.commitTransaction(tx)
|
||||
err := env.commitTransaction(tx, proc)
|
||||
switch {
|
||||
case core.IsNonceErr(err) || core.IsInvalidTxErr(err):
|
||||
current.remove.Add(tx.Hash())
|
||||
env.remove.Add(tx.Hash())
|
||||
|
||||
if glog.V(logger.Detail) {
|
||||
glog.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
|
||||
}
|
||||
case state.IsGasLimitErr(err):
|
||||
from, _ := tx.From()
|
||||
// ignore the transactor so no nonce errors will be thrown for this account
|
||||
// next time the worker is run, they'll be picked up again.
|
||||
current.ignoredTransactors.Add(from)
|
||||
env.ignoredTransactors.Add(from)
|
||||
|
||||
glog.V(logger.Detail).Infof("Gas limit reached for (%x) in this block. Continue to try smaller txs\n", from[:4])
|
||||
default:
|
||||
current.tcount++
|
||||
env.tcount++
|
||||
}
|
||||
}
|
||||
|
||||
self.current.block.Header().GasUsed = self.current.totalUsedGas
|
||||
}
|
||||
|
||||
func (self *worker) commitTransaction(tx *types.Transaction) error {
|
||||
snap := self.current.state.Copy()
|
||||
receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true)
|
||||
func (env *environment) 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)
|
||||
if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) {
|
||||
self.current.state.Set(snap)
|
||||
env.state.Set(snap)
|
||||
return err
|
||||
}
|
||||
|
||||
self.current.block.AddTransaction(tx)
|
||||
self.current.block.AddReceipt(receipt)
|
||||
|
||||
env.txs = append(env.txs, tx)
|
||||
env.receipts = append(env.receipts, receipt)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
|
||||
if b.BlockHeader == nil {
|
||||
continue // OK - block is supposed to be invalid, continue with next block
|
||||
} else {
|
||||
return fmt.Errorf("Block RLP decoding failed when expected to succeed: ", err)
|
||||
return fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err)
|
||||
}
|
||||
}
|
||||
// RLP decoding worked, try to insert into chain:
|
||||
@ -254,7 +254,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
|
||||
if b.BlockHeader == nil {
|
||||
continue // OK - block is supposed to be invalid, continue with next block
|
||||
} else {
|
||||
return fmt.Errorf("Block insertion into chain failed: ", err)
|
||||
return fmt.Errorf("Block insertion into chain failed: %v", err)
|
||||
}
|
||||
}
|
||||
if b.BlockHeader == nil {
|
||||
@ -262,7 +262,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
|
||||
}
|
||||
err = t.validateBlockHeader(b.BlockHeader, cb.Header())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Block header validation failed: ", err)
|
||||
return fmt.Errorf("Block header validation failed: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -286,7 +286,7 @@ func (s *BlockTest) validateBlockHeader(h *btHeader, h2 *types.Header) error {
|
||||
|
||||
expectedNonce := mustConvertBytes(h.Nonce)
|
||||
if !bytes.Equal(expectedNonce, h2.Nonce[:]) {
|
||||
return fmt.Errorf("Nonce: expected: %v, decoded: %v", expectedNonce, h2.Nonce[:])
|
||||
return fmt.Errorf("Nonce: expected: %v, decoded: %v", expectedNonce, h2.Nonce)
|
||||
}
|
||||
|
||||
expectedNumber := mustConvertBigInt(h.Number, 16)
|
||||
@ -423,9 +423,8 @@ func mustConvertHeader(in btHeader) *types.Header {
|
||||
GasLimit: mustConvertBigInt(in.GasLimit, 16),
|
||||
Difficulty: mustConvertBigInt(in.Difficulty, 16),
|
||||
Time: mustConvertUint(in.Timestamp, 16),
|
||||
Nonce: types.EncodeNonce(mustConvertUint(in.Nonce, 16)),
|
||||
}
|
||||
// XXX cheats? :-)
|
||||
header.SetNonce(mustConvertUint(in.Nonce, 16))
|
||||
return header
|
||||
}
|
||||
|
||||
|
10
xeth/xeth.go
10
xeth/xeth.go
@ -209,8 +209,8 @@ func (self *XEth) AtStateNum(num int64) *XEth {
|
||||
// - could be removed in favour of mining on testdag (natspec e2e + networking)
|
||||
// + filters
|
||||
func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, txc uint64) (uint64, *XEth) {
|
||||
|
||||
block := self.backend.ChainManager().NewBlock(address)
|
||||
chain := self.backend.ChainManager()
|
||||
header := chain.CurrentBlock().Header()
|
||||
coinbase := statedb.GetStateObject(address)
|
||||
coinbase.SetGasLimit(big.NewInt(10000000))
|
||||
txs := self.backend.TxPool().GetQueuedTransactions()
|
||||
@ -218,7 +218,7 @@ func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, t
|
||||
for i := 0; i < len(txs); i++ {
|
||||
for _, tx := range txs {
|
||||
if tx.Nonce() == txc {
|
||||
_, _, err := core.ApplyMessage(core.NewEnv(statedb, self.backend.ChainManager(), tx, block), tx, coinbase)
|
||||
_, _, err := core.ApplyMessage(core.NewEnv(statedb, self.backend.ChainManager(), tx, header), tx, coinbase)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -845,8 +845,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
|
||||
msg.gasPrice = self.DefaultGasPrice()
|
||||
}
|
||||
|
||||
block := self.CurrentBlock()
|
||||
vmenv := core.NewEnv(statedb, self.backend.ChainManager(), msg, block)
|
||||
header := self.CurrentBlock().Header()
|
||||
vmenv := core.NewEnv(statedb, self.backend.ChainManager(), msg, header)
|
||||
|
||||
res, gas, err := core.ApplyMessage(vmenv, msg, from)
|
||||
return common.ToHex(res), gas.String(), err
|
||||
|
Loading…
Reference in New Issue
Block a user