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) {
|
func newChain(size int) (chain []*types.Block) {
|
||||||
var parentHash common.Hash
|
var parentHash common.Hash
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
block := types.NewBlock(parentHash, common.Address{}, common.Hash{}, new(big.Int), 0, nil)
|
head := &types.Header{ParentHash: parentHash, Number: big.NewInt(int64(i))}
|
||||||
block.Header().Number = big.NewInt(int64(i))
|
block := types.NewBlock(head, nil, nil, nil)
|
||||||
chain = append(chain, block)
|
chain = append(chain, block)
|
||||||
parentHash = block.Hash()
|
parentHash = block.Hash()
|
||||||
}
|
}
|
||||||
return
|
return chain
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertChainCache(cache *BlockCache, chain []*types.Block) {
|
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) {
|
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 := statedb.GetOrNewStateObject(block.Coinbase())
|
||||||
coinbase.SetGasLimit(block.Header().GasLimit)
|
coinbase.SetGasLimit(block.GasLimit())
|
||||||
|
|
||||||
// Process the transactions on to parent state
|
// Process the transactions on to parent state
|
||||||
receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
|
receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
|
||||||
@ -69,11 +69,11 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block
|
|||||||
return receipts, nil
|
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
|
// If we are mining this block and validating we want to set the logs back to 0
|
||||||
|
|
||||||
cb := statedb.GetStateObject(coinbase.Address())
|
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)) {
|
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -108,12 +108,13 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
|
|||||||
totalUsedGas = big.NewInt(0)
|
totalUsedGas = big.NewInt(0)
|
||||||
err error
|
err error
|
||||||
cumulativeSum = new(big.Int)
|
cumulativeSum = new(big.Int)
|
||||||
|
header = block.Header()
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
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)) {
|
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -142,11 +143,10 @@ func (sm *BlockProcessor) RetryProcess(block *types.Block) (logs state.Logs, err
|
|||||||
sm.mutex.Lock()
|
sm.mutex.Lock()
|
||||||
defer sm.mutex.Unlock()
|
defer sm.mutex.Unlock()
|
||||||
|
|
||||||
header := block.Header()
|
if !sm.bc.HasBlock(block.ParentHash()) {
|
||||||
if !sm.bc.HasBlock(header.ParentHash) {
|
return nil, ParentError(block.ParentHash())
|
||||||
return nil, ParentError(header.ParentHash)
|
|
||||||
}
|
}
|
||||||
parent := sm.bc.GetBlock(header.ParentHash)
|
parent := sm.bc.GetBlock(block.ParentHash())
|
||||||
|
|
||||||
// FIXME Change to full header validation. See #1225
|
// FIXME Change to full header validation. See #1225
|
||||||
errch := make(chan bool)
|
errch := make(chan bool)
|
||||||
@ -168,30 +168,32 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, err erro
|
|||||||
sm.mutex.Lock()
|
sm.mutex.Lock()
|
||||||
defer sm.mutex.Unlock()
|
defer sm.mutex.Unlock()
|
||||||
|
|
||||||
header := block.Header()
|
if sm.bc.HasBlock(block.Hash()) {
|
||||||
if sm.bc.HasBlock(header.Hash()) {
|
return nil, &KnownBlockError{block.Number(), block.Hash()}
|
||||||
return nil, &KnownBlockError{header.Number, header.Hash()}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sm.bc.HasBlock(header.ParentHash) {
|
if !sm.bc.HasBlock(block.ParentHash()) {
|
||||||
return nil, ParentError(header.ParentHash)
|
return nil, ParentError(block.ParentHash())
|
||||||
}
|
}
|
||||||
parent := sm.bc.GetBlock(header.ParentHash)
|
parent := sm.bc.GetBlock(block.ParentHash())
|
||||||
return sm.processWithParent(block, parent)
|
return sm.processWithParent(block, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) {
|
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)
|
// Create a new state based on the parent's root (e.g., create copy)
|
||||||
state := state.New(parent.Root(), sm.db)
|
state := state.New(parent.Root(), sm.db)
|
||||||
|
header := block.Header()
|
||||||
|
uncles := block.Uncles()
|
||||||
|
txs := block.Transactions()
|
||||||
|
|
||||||
// Block validation
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// There can be at most two uncles
|
// There can be at most two uncles
|
||||||
if len(block.Uncles()) > 2 {
|
if len(uncles) > 2 {
|
||||||
return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
|
return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(uncles))
|
||||||
}
|
}
|
||||||
|
|
||||||
receipts, err := sm.TransitionState(state, parent, block, false)
|
receipts, err := sm.TransitionState(state, parent, block, false)
|
||||||
@ -199,8 +201,6 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
header := block.Header()
|
|
||||||
|
|
||||||
// Validate the received block's bloom with the one derived from the generated receipts.
|
// Validate the received block's bloom with the one derived from the generated receipts.
|
||||||
// For valid blocks this should always validate to true.
|
// For valid blocks this should always validate to true.
|
||||||
rbloom := types.CreateBloom(receipts)
|
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)]]))
|
// 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
|
// 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 {
|
if txSha != header.TxHash {
|
||||||
err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
|
err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
|
||||||
return
|
return
|
||||||
@ -225,7 +225,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify UncleHash before running other uncle validations
|
// Verify UncleHash before running other uncle validations
|
||||||
unclesSha := block.CalculateUnclesHash()
|
unclesSha := types.CalcUncleHash(uncles)
|
||||||
if unclesSha != header.UncleHash {
|
if unclesSha != header.UncleHash {
|
||||||
err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
|
err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
|
||||||
return
|
return
|
||||||
@ -236,7 +236,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Accumulate static rewards; block reward, uncle's and uncle inclusion.
|
// 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)
|
// Commit state objects/accounts to a temporary trie (does not save)
|
||||||
// used to calculate the state root.
|
// used to calculate the state root.
|
||||||
@ -260,11 +260,34 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
|||||||
return state.Logs(), nil
|
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 {
|
func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error {
|
||||||
ancestors := set.New()
|
ancestors := set.New()
|
||||||
uncles := set.New()
|
uncles := set.New()
|
||||||
ancestorHeaders := make(map[common.Hash]*types.Header)
|
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()
|
ancestorHeaders[ancestor.Hash()] = ancestor.Header()
|
||||||
ancestors.Add(ancestor.Hash())
|
ancestors.Add(ancestor.Hash())
|
||||||
// Include ancestors uncles in the uncle set. Uncles must be unique.
|
// 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
|
// TODO: remove backward compatibility
|
||||||
var (
|
var (
|
||||||
parent = sm.bc.GetBlock(block.Header().ParentHash)
|
parent = sm.bc.GetBlock(block.ParentHash())
|
||||||
state = state.New(parent.Root(), sm.db)
|
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))
|
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 {
|
if expd.Cmp(block.Difficulty) != 0 {
|
||||||
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
|
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
|
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) {
|
func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) {
|
||||||
var rdata []byte
|
var rdata []byte
|
||||||
rdata, err = db.Get(append(receiptsPre, bhash[:]...))
|
rdata, err = db.Get(append(receiptsPre, bhash[:]...))
|
||||||
|
@ -26,20 +26,18 @@ func proc() (*BlockProcessor, *ChainManager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNumber(t *testing.T) {
|
func TestNumber(t *testing.T) {
|
||||||
_, chain := proc()
|
|
||||||
block1 := chain.NewBlock(common.Address{})
|
|
||||||
block1.Header().Number = big.NewInt(3)
|
|
||||||
block1.Header().Time--
|
|
||||||
|
|
||||||
pow := ezp.New()
|
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 {
|
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{})
|
header = makeHeader(chain.Genesis(), 0, bp.db, 0)
|
||||||
err = ValidateHeader(pow, block1.Header(), chain.Genesis().Header(), false)
|
err = ValidateHeader(pow, header, chain.Genesis().Header(), false)
|
||||||
if err == BlockNumberErr {
|
if err == BlockNumberErr {
|
||||||
t.Errorf("didn't expect block number error")
|
t.Errorf("didn't expect block number error")
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,8 @@ var (
|
|||||||
|
|
||||||
// Utility functions for making chains on the fly
|
// Utility functions for making chains on the fly
|
||||||
// Exposed for sake of testing from other packages (eg. go-ethash)
|
// 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 {
|
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 {
|
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)
|
return newCanonical(n, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// block time is fixed at 10 seconds
|
// makeHeader creates the header for a new empty block, simulating
|
||||||
func newBlockFromParent(addr common.Address, parent *types.Block) *types.Block {
|
// what miner would do. We seed chains by the first byte of the coinbase.
|
||||||
block := types.NewBlock(parent.Hash(), addr, parent.Root(), common.BigPow(2, 32), 0, nil)
|
func makeHeader(parent *types.Block, i int, db common.Database, seed int) *types.Header {
|
||||||
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 {
|
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
addr[0], addr[19] = byte(seed), byte(i)
|
addr[0], addr[19] = byte(seed), byte(i) // 'random' coinbase
|
||||||
block := newBlockFromParent(addr, parent)
|
time := parent.Time() + 10 // block time is fixed at 10 seconds
|
||||||
state := state.New(block.Root(), db)
|
|
||||||
|
// ensure that the block's coinbase has the block reward in the state.
|
||||||
|
state := state.New(parent.Root(), db)
|
||||||
cbase := state.GetOrNewStateObject(addr)
|
cbase := state.GetOrNewStateObject(addr)
|
||||||
cbase.SetGasLimit(CalcGasLimit(parent))
|
cbase.SetGasLimit(CalcGasLimit(parent))
|
||||||
cbase.AddBalance(BlockReward)
|
cbase.AddBalance(BlockReward)
|
||||||
state.Update()
|
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
|
// makeChain creates a valid chain of empty blocks.
|
||||||
// Runs ProcessWithParent to get proper state roots
|
|
||||||
func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Database, seed int) types.Blocks {
|
func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Database, seed int) types.Blocks {
|
||||||
bman.bc.currentBlock = parent
|
bman.bc.currentBlock = parent
|
||||||
blocks := make(types.Blocks, max)
|
blocks := make(types.Blocks, max)
|
||||||
for i := 0; i < max; i++ {
|
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)
|
_, err := bman.processWithParent(block, parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("process with parent failed", err)
|
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
|
// 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) {
|
func newCanonical(n int, db common.Database) (*BlockProcessor, error) {
|
||||||
eventMux := &event.TypeMux{}
|
eventMux := &event.TypeMux{}
|
||||||
|
|
||||||
|
@ -38,23 +38,24 @@ const (
|
|||||||
maxTimeFutureBlocks = 30
|
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)
|
diff := new(big.Int)
|
||||||
|
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
|
||||||
adjust := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor)
|
if big.NewInt(time-parentTime).Cmp(params.DurationLimit) < 0 {
|
||||||
if big.NewInt(int64(block.Time)-int64(parent.Time)).Cmp(params.DurationLimit) < 0 {
|
diff.Add(parentDiff, adjust)
|
||||||
diff.Add(parent.Difficulty, adjust)
|
|
||||||
} else {
|
} else {
|
||||||
diff.Sub(parent.Difficulty, adjust)
|
diff.Sub(parentDiff, adjust)
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff.Cmp(params.MinimumDifficulty) < 0 {
|
if diff.Cmp(params.MinimumDifficulty) < 0 {
|
||||||
return params.MinimumDifficulty
|
return params.MinimumDifficulty
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalcTD computes the total difficulty of block.
|
||||||
func CalcTD(block, parent *types.Block) *big.Int {
|
func CalcTD(block, parent *types.Block) *big.Int {
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return block.Difficulty()
|
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)
|
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 {
|
func CalcGasLimit(parent *types.Block) *big.Int {
|
||||||
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
|
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
|
||||||
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
|
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 := new(big.Int).Sub(parent.GasLimit(), decay)
|
||||||
gl = gl.Add(gl, contrib)
|
gl = gl.Add(gl, contrib)
|
||||||
gl = gl.Add(gl, big.NewInt(1))
|
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 {
|
if gl.Cmp(params.GenesisGasLimit) < 0 {
|
||||||
gl2 := new(big.Int).Add(parent.GasLimit(), decay)
|
gl.Add(parent.GasLimit(), decay)
|
||||||
return common.BigMin(params.GenesisGasLimit, gl2)
|
gl.Set(common.BigMin(gl, params.GenesisGasLimit))
|
||||||
}
|
}
|
||||||
return gl
|
return gl
|
||||||
}
|
}
|
||||||
@ -255,50 +258,11 @@ func (bc *ChainManager) makeCache() {
|
|||||||
bc.cache = NewBlockCache(blockCacheLimit)
|
bc.cache = NewBlockCache(blockCacheLimit)
|
||||||
}
|
}
|
||||||
// load in last `blockCacheLimit` - 1 blocks. Last block is the current.
|
// load in last `blockCacheLimit` - 1 blocks. Last block is the current.
|
||||||
ancestors := bc.GetAncestors(bc.currentBlock, blockCacheLimit-1)
|
for _, block := range bc.GetBlocksFromHash(bc.currentBlock.Hash(), blockCacheLimit) {
|
||||||
ancestors = append(ancestors, bc.currentBlock)
|
|
||||||
for _, block := range ancestors {
|
|
||||||
bc.cache.Push(block)
|
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() {
|
func (bc *ChainManager) Reset() {
|
||||||
bc.mu.Lock()
|
bc.mu.Lock()
|
||||||
defer bc.mu.Unlock()
|
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
|
// non blocking version
|
||||||
func (self *ChainManager) getBlockByNumber(num uint64) *types.Block {
|
func (self *ChainManager) getBlockByNumber(num uint64) *types.Block {
|
||||||
key, _ := self.blockDb.Get(append(blockNumPre, big.NewInt(int64(num)).Bytes()...))
|
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
|
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
|
// setTotalDifficulty updates the TD of the chain manager. Note, this function
|
||||||
// assumes that the `mu` mutex is held!
|
// assumes that the `mu` mutex is held!
|
||||||
func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
|
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)
|
return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max)
|
||||||
}
|
}
|
||||||
|
|
||||||
block.SetQueued(true)
|
|
||||||
self.futureBlocks.Push(block)
|
self.futureBlocks.Push(block)
|
||||||
stats.queued++
|
stats.queued++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if IsParentErr(err) && self.futureBlocks.Has(block.ParentHash()) {
|
if IsParentErr(err) && self.futureBlocks.Has(block.ParentHash()) {
|
||||||
block.SetQueued(true)
|
|
||||||
self.futureBlocks.Push(block)
|
self.futureBlocks.Push(block)
|
||||||
stats.queued++
|
stats.queued++
|
||||||
continue
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ func TestBrokenChain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestChainInsertions(t *testing.T) {
|
func TestChainInsertions(t *testing.T) {
|
||||||
t.Skip() // travil fails.
|
t.Skip("Skipped: outdated test files")
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ func TestChainInsertions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestChainMultipleInsertions(t *testing.T) {
|
func TestChainMultipleInsertions(t *testing.T) {
|
||||||
t.Skip() // travil fails.
|
t.Skip("Skipped: outdated test files")
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
|
||||||
@ -346,8 +346,8 @@ func TestChainMultipleInsertions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAncestors(t *testing.T) {
|
func TestGetBlocksFromHash(t *testing.T) {
|
||||||
t.Skip() // travil fails.
|
t.Skip("Skipped: outdated test files")
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
chainMan := theChainManager(db, t)
|
chainMan := theChainManager(db, t)
|
||||||
@ -361,8 +361,8 @@ func TestGetAncestors(t *testing.T) {
|
|||||||
chainMan.write(block)
|
chainMan.write(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
ancestors := chainMan.GetAncestors(chain[len(chain)-1], 4)
|
blocks := chainMan.GetBlocksFromHash(chain[len(chain)-1].Hash(), 4)
|
||||||
fmt.Println(ancestors)
|
fmt.Println(blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
type bproc struct{}
|
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 {
|
func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block {
|
||||||
var chain []*types.Block
|
var chain []*types.Block
|
||||||
for i, difficulty := range d {
|
for i, difficulty := range d {
|
||||||
header := &types.Header{Number: big.NewInt(int64(i + 1)), Difficulty: big.NewInt(int64(difficulty))}
|
header := &types.Header{
|
||||||
block := types.NewBlockWithHeader(header)
|
Coinbase: common.Address{seed},
|
||||||
copy(block.HeaderHash[:2], []byte{byte(i + 1), seed})
|
Number: big.NewInt(int64(i + 1)),
|
||||||
if i == 0 {
|
Difficulty: big.NewInt(int64(difficulty)),
|
||||||
block.ParentHeaderHash = genesis.Hash()
|
|
||||||
} else {
|
|
||||||
copy(block.ParentHeaderHash[:2], []byte{byte(i), seed})
|
|
||||||
}
|
}
|
||||||
|
if i == 0 {
|
||||||
|
header.ParentHash = genesis.Hash()
|
||||||
|
} else {
|
||||||
|
header.ParentHash = chain[i-1].Hash()
|
||||||
|
}
|
||||||
|
block := types.NewBlockWithHeader(header)
|
||||||
chain = append(chain, block)
|
chain = append(chain, block)
|
||||||
}
|
}
|
||||||
return chain
|
return chain
|
||||||
@ -399,7 +401,6 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReorgLongest(t *testing.T) {
|
func TestReorgLongest(t *testing.T) {
|
||||||
t.Skip("skipped while cache is removed")
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
genesis := GenesisBlock(0, db)
|
genesis := GenesisBlock(0, db)
|
||||||
bc := chm(genesis, db)
|
bc := chm(genesis, db)
|
||||||
@ -419,7 +420,6 @@ func TestReorgLongest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReorgShortest(t *testing.T) {
|
func TestReorgShortest(t *testing.T) {
|
||||||
t.Skip("skipped while cache is removed")
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
genesis := GenesisBlock(0, db)
|
genesis := GenesisBlock(0, db)
|
||||||
bc := chm(genesis, db)
|
bc := chm(genesis, db)
|
||||||
|
@ -11,38 +11,18 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
// GenesisBlock creates a genesis block with the given nonce.
|
||||||
* This is the special genesis block.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var ZeroHash256 = make([]byte, 32)
|
|
||||||
var ZeroHash160 = make([]byte, 20)
|
|
||||||
var ZeroHash512 = make([]byte, 64)
|
|
||||||
|
|
||||||
func GenesisBlock(nonce uint64, db common.Database) *types.Block {
|
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 {
|
var accounts map[string]struct {
|
||||||
Balance string
|
Balance string
|
||||||
Code string
|
Code string
|
||||||
}
|
}
|
||||||
err := json.Unmarshal(GenesisAccounts, &accounts)
|
err := json.Unmarshal(GenesisAccounts, &accounts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("enable to decode genesis json data:", err)
|
fmt.Println("unable to decode genesis json data:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
statedb := state.New(common.Hash{}, db)
|
||||||
statedb := state.New(genesis.Root(), db)
|
|
||||||
for addr, account := range accounts {
|
for addr, account := range accounts {
|
||||||
codedAddr := common.Hex2Bytes(addr)
|
codedAddr := common.Hex2Bytes(addr)
|
||||||
accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr))
|
accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr))
|
||||||
@ -51,10 +31,15 @@ func GenesisBlock(nonce uint64, db common.Database) *types.Block {
|
|||||||
statedb.UpdateStateObject(accountState)
|
statedb.UpdateStateObject(accountState)
|
||||||
}
|
}
|
||||||
statedb.Sync()
|
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(`{
|
var GenesisAccounts = []byte(`{
|
||||||
|
@ -73,16 +73,17 @@ func MessageGasValue(msg Message) *big.Int {
|
|||||||
return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
|
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)
|
igas := new(big.Int).Set(params.TxGas)
|
||||||
for _, byt := range msg.Data() {
|
for _, byt := range data {
|
||||||
if byt != 0 {
|
if byt != 0 {
|
||||||
igas.Add(igas, params.TxDataNonZeroGas)
|
igas.Add(igas, params.TxDataNonZeroGas)
|
||||||
} else {
|
} else {
|
||||||
igas.Add(igas, params.TxDataZeroGas)
|
igas.Add(igas, params.TxDataZeroGas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return igas
|
return igas
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +196,7 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
|
|||||||
sender, _ := self.From() // err checked in preCheck
|
sender, _ := self.From() // err checked in preCheck
|
||||||
|
|
||||||
// Pay intrinsic gas
|
// 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)
|
return nil, nil, InvalidTxError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should supply enough intrinsic gas
|
// Should supply enough intrinsic gas
|
||||||
if tx.Gas().Cmp(IntrinsicGas(tx)) < 0 {
|
if tx.Gas().Cmp(IntrinsicGas(tx.Data())) < 0 {
|
||||||
return ErrIntrinsicGas
|
return ErrIntrinsicGas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,71 +15,59 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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 {
|
type Header struct {
|
||||||
// Hash to the previous block
|
ParentHash common.Hash // Hash to the previous block
|
||||||
ParentHash common.Hash
|
UncleHash common.Hash // Uncles of this block
|
||||||
// Uncles of this block
|
Coinbase common.Address // The coin base address
|
||||||
UncleHash common.Hash
|
Root common.Hash // Block Trie state
|
||||||
// The coin base address
|
TxHash common.Hash // Tx sha
|
||||||
Coinbase common.Address
|
ReceiptHash common.Hash // Receipt sha
|
||||||
// Block Trie state
|
Bloom Bloom // Bloom
|
||||||
Root common.Hash
|
Difficulty *big.Int // Difficulty for the current block
|
||||||
// Tx sha
|
Number *big.Int // The block number
|
||||||
TxHash common.Hash
|
GasLimit *big.Int // Gas limit
|
||||||
// Receipt sha
|
GasUsed *big.Int // Gas used
|
||||||
ReceiptHash common.Hash
|
Time uint64 // Creation time
|
||||||
// Bloom
|
Extra []byte // Extra data
|
||||||
Bloom Bloom
|
MixDigest common.Hash // for quick difficulty verification
|
||||||
// Difficulty for the current block
|
Nonce BlockNonce
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Header) Hash() common.Hash {
|
func (h *Header) Hash() common.Hash {
|
||||||
return rlpHash(self.rlpData(true))
|
return rlpHash(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Header) HashNoNonce() common.Hash {
|
func (h *Header) HashNoNonce() common.Hash {
|
||||||
return rlpHash(self.rlpData(false))
|
return rlpHash([]interface{}{
|
||||||
}
|
h.ParentHash,
|
||||||
|
h.UncleHash,
|
||||||
func (self *Header) rlpData(withNonce bool) []interface{} {
|
h.Coinbase,
|
||||||
fields := []interface{}{
|
h.Root,
|
||||||
self.ParentHash,
|
h.TxHash,
|
||||||
self.UncleHash,
|
h.ReceiptHash,
|
||||||
self.Coinbase,
|
h.Bloom,
|
||||||
self.Root,
|
h.Difficulty,
|
||||||
self.TxHash,
|
h.Number,
|
||||||
self.ReceiptHash,
|
h.GasLimit,
|
||||||
self.Bloom,
|
h.GasUsed,
|
||||||
self.Difficulty,
|
h.Time,
|
||||||
self.Number,
|
h.Extra,
|
||||||
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) UnmarshalJSON(data []byte) error {
|
func (h *Header) UnmarshalJSON(data []byte) error {
|
||||||
@ -112,20 +100,14 @@ func rlpHash(x interface{}) (h common.Hash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Block struct {
|
type Block struct {
|
||||||
// Preset Hash for mock (Tests)
|
|
||||||
HeaderHash common.Hash
|
|
||||||
ParentHeaderHash common.Hash
|
|
||||||
// ^^^^ ignore ^^^^
|
|
||||||
|
|
||||||
header *Header
|
header *Header
|
||||||
uncles []*Header
|
uncles []*Header
|
||||||
transactions Transactions
|
transactions Transactions
|
||||||
Td *big.Int
|
receipts Receipts
|
||||||
queued bool // flag for blockpool to skip TD check
|
|
||||||
|
|
||||||
|
Td *big.Int
|
||||||
|
queued bool // flag for blockpool to skip TD check
|
||||||
ReceivedAt time.Time
|
ReceivedAt time.Time
|
||||||
|
|
||||||
receipts Receipts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageBlock defines the RLP encoding of a Block stored in the
|
// StorageBlock defines the RLP encoding of a Block stored in the
|
||||||
@ -148,43 +130,90 @@ type storageblock struct {
|
|||||||
TD *big.Int
|
TD *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra []byte) *Block {
|
var (
|
||||||
header := &Header{
|
emptyRootHash = DeriveSha(Transactions{})
|
||||||
Root: root,
|
emptyUncleHash = CalcUncleHash(nil)
|
||||||
ParentHash: parentHash,
|
)
|
||||||
Coinbase: coinbase,
|
|
||||||
Difficulty: difficulty,
|
// NewBlock creates a new block. The input data is copied,
|
||||||
Time: uint64(time.Now().Unix()),
|
// changes to header and to the field values will not affect the
|
||||||
Extra: extra,
|
// block.
|
||||||
GasUsed: new(big.Int),
|
//
|
||||||
GasLimit: new(big.Int),
|
// The values of TxHash, UncleHash, ReceiptHash and Bloom in header
|
||||||
Number: new(big.Int),
|
// 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 {
|
||||||
func (self *Header) SetNonce(nonce uint64) {
|
b.header.ReceiptHash = DeriveSha(Receipts(receipts))
|
||||||
binary.BigEndian.PutUint64(self.Nonce[:], nonce)
|
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 {
|
func NewBlockWithHeader(header *Header) *Block {
|
||||||
return &Block{header: header}
|
return &Block{header: copyHeader(header)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Block) ValidateFields() error {
|
func copyHeader(h *Header) *Header {
|
||||||
if self.header == nil {
|
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")
|
return fmt.Errorf("header is nil")
|
||||||
}
|
}
|
||||||
for i, transaction := range self.transactions {
|
for i, transaction := range b.transactions {
|
||||||
if transaction == nil {
|
if transaction == nil {
|
||||||
return fmt.Errorf("transaction %d is nil", i)
|
return fmt.Errorf("transaction %d is nil", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, uncle := range self.uncles {
|
for i, uncle := range b.uncles {
|
||||||
if uncle == nil {
|
if uncle == nil {
|
||||||
return fmt.Errorf("uncle %d is nil", i)
|
return fmt.Errorf("uncle %d is nil", i)
|
||||||
}
|
}
|
||||||
@ -192,64 +221,48 @@ func (self *Block) ValidateFields() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Block) DecodeRLP(s *rlp.Stream) error {
|
func (b *Block) DecodeRLP(s *rlp.Stream) error {
|
||||||
var eb extblock
|
var eb extblock
|
||||||
if err := s.Decode(&eb); err != nil {
|
if err := s.Decode(&eb); err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Block) EncodeRLP(w io.Writer) error {
|
func (b Block) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, extblock{
|
return rlp.Encode(w, extblock{
|
||||||
Header: self.header,
|
Header: b.header,
|
||||||
Txs: self.transactions,
|
Txs: b.transactions,
|
||||||
Uncles: self.uncles,
|
Uncles: b.uncles,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error {
|
func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error {
|
||||||
var sb storageblock
|
var sb storageblock
|
||||||
if err := s.Decode(&sb); err != nil {
|
if err := s.Decode(&sb); err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self StorageBlock) EncodeRLP(w io.Writer) error {
|
func (b StorageBlock) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, storageblock{
|
return rlp.Encode(w, storageblock{
|
||||||
Header: self.header,
|
Header: b.header,
|
||||||
Txs: self.transactions,
|
Txs: b.transactions,
|
||||||
Uncles: self.uncles,
|
Uncles: b.uncles,
|
||||||
TD: self.Td,
|
TD: b.Td,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Block) Header() *Header {
|
// TODO: copies
|
||||||
return self.header
|
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 {
|
func (b *Block) Transaction(hash common.Hash) *Transaction {
|
||||||
return self.uncles
|
for _, transaction := range b.transactions {
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
if transaction.Hash() == hash {
|
if transaction.Hash() == hash {
|
||||||
return transaction
|
return transaction
|
||||||
}
|
}
|
||||||
@ -257,74 +270,33 @@ func (self *Block) Transaction(hash common.Hash) *Transaction {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Block) SetTransactions(transactions Transactions) {
|
func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) }
|
||||||
self.transactions = transactions
|
func (b *Block) GasLimit() *big.Int { return new(big.Int).Set(b.header.GasLimit) }
|
||||||
self.header.TxHash = DeriveSha(transactions)
|
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) AddTransaction(transaction *Transaction) {
|
|
||||||
self.transactions = append(self.transactions, transaction)
|
func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
|
||||||
self.SetTransactions(self.transactions)
|
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 {
|
func (b *Block) Size() common.StorageSize {
|
||||||
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 {
|
|
||||||
c := writeCounter(0)
|
c := writeCounter(0)
|
||||||
rlp.Encode(&c, self)
|
rlp.Encode(&c, b)
|
||||||
return common.StorageSize(c)
|
return common.StorageSize(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,48 +307,32 @@ func (c *writeCounter) Write(b []byte) (int, error) {
|
|||||||
return len(b), nil
|
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
|
// 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 {
|
func (b *Block) Hash() common.Hash {
|
||||||
if (self.HeaderHash != common.Hash{}) {
|
return b.header.Hash()
|
||||||
return self.HeaderHash
|
|
||||||
} else {
|
|
||||||
return self.header.Hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Block) ParentHash() common.Hash {
|
func (b *Block) String() string {
|
||||||
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 {
|
|
||||||
str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v {
|
str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v {
|
||||||
MinerHash: %x
|
MinerHash: %x
|
||||||
%v
|
%v
|
||||||
@ -385,20 +341,11 @@ Transactions:
|
|||||||
Uncles:
|
Uncles:
|
||||||
%v
|
%v
|
||||||
}
|
}
|
||||||
`, self.Number(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles)
|
`, b.Number(), b.Size(), b.Td, b.header.HashNoNonce(), b.header, b.transactions, b.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Header) String() string {
|
func (h *Header) String() string {
|
||||||
return fmt.Sprintf(`Header(%x):
|
return fmt.Sprintf(`Header(%x):
|
||||||
[
|
[
|
||||||
ParentHash: %x
|
ParentHash: %x
|
||||||
@ -414,9 +361,9 @@ func (self *Header) String() string {
|
|||||||
GasUsed: %v
|
GasUsed: %v
|
||||||
Time: %v
|
Time: %v
|
||||||
Extra: %s
|
Extra: %s
|
||||||
MixDigest: %x
|
MixDigest: %x
|
||||||
Nonce: %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
|
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 (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 {
|
type VMEnv struct {
|
||||||
state *state.StateDB
|
state *state.StateDB
|
||||||
block *types.Block
|
header *types.Header
|
||||||
msg Message
|
msg Message
|
||||||
depth int
|
depth int
|
||||||
chain *ChainManager
|
chain *ChainManager
|
||||||
typ vm.Type
|
typ vm.Type
|
||||||
// structured logging
|
// structured logging
|
||||||
logs []vm.StructLog
|
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{
|
return &VMEnv{
|
||||||
chain: chain,
|
chain: chain,
|
||||||
state: state,
|
state: state,
|
||||||
block: block,
|
header: header,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
typ: vm.StdVmTy,
|
typ: vm.StdVmTy,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
|
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) BlockNumber() *big.Int { return self.header.Number }
|
||||||
func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() }
|
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
|
||||||
func (self *VMEnv) Time() int64 { return self.block.Time() }
|
func (self *VMEnv) Time() int64 { return int64(self.header.Time) }
|
||||||
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
|
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
|
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
|
||||||
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
|
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
|
||||||
func (self *VMEnv) State() *state.StateDB { return self.state }
|
func (self *VMEnv) State() *state.StateDB { return self.state }
|
||||||
func (self *VMEnv) Depth() int { return self.depth }
|
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.
|
// createBlock assembles a new block at the given chain height.
|
||||||
func createBlock(i int, parent, hash common.Hash) *types.Block {
|
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 := types.NewBlockWithHeader(header)
|
||||||
block.HeaderHash = hash
|
block.HeaderHash = hash
|
||||||
block.ParentHeaderHash = parent
|
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)
|
glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
|
||||||
|
|
||||||
// Mine
|
// Mine
|
||||||
nonce, mixDigest := self.pow.Search(block, stop)
|
nonce, mixDigest := self.pow.Search(block, stop)
|
||||||
if nonce != 0 {
|
if nonce != 0 {
|
||||||
block.SetNonce(nonce)
|
self.returnCh <- block.WithMiningResult(nonce, common.BytesToHash(mixDigest))
|
||||||
block.Header().MixDigest = common.BytesToHash(mixDigest)
|
|
||||||
self.returnCh <- block
|
|
||||||
} else {
|
} else {
|
||||||
self.returnCh <- nil
|
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
|
// Make sure the external miner was working on the right hash
|
||||||
if a.currentWork != nil && a.work != nil {
|
if a.currentWork != nil && a.work != nil {
|
||||||
a.currentWork.SetNonce(nonce)
|
a.returnCh <- a.currentWork.WithMiningResult(nonce, mixDigest)
|
||||||
a.currentWork.Header().MixDigest = mixDigest
|
|
||||||
a.returnCh <- a.currentWork
|
|
||||||
//a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()}
|
//a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()}
|
||||||
return true
|
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
|
// environment is the workers current environment and holds
|
||||||
// all of the current state information
|
// all of the current state information
|
||||||
type environment struct {
|
type environment struct {
|
||||||
totalUsedGas *big.Int // total gas usage in the cycle
|
|
||||||
state *state.StateDB // apply state changes here
|
state *state.StateDB // apply state changes here
|
||||||
coinbase *state.StateObject // the miner's account
|
coinbase *state.StateObject // the miner's account
|
||||||
block *types.Block // the new block
|
|
||||||
ancestors *set.Set // ancestor set (used for checking uncle parent validity)
|
ancestors *set.Set // ancestor set (used for checking uncle parent validity)
|
||||||
family *set.Set // family set (used for checking uncle invalidity)
|
family *set.Set // family set (used for checking uncle invalidity)
|
||||||
uncles *set.Set // uncle set
|
uncles *set.Set // uncle set
|
||||||
@ -63,22 +61,12 @@ type environment struct {
|
|||||||
ownedAccounts *set.Set
|
ownedAccounts *set.Set
|
||||||
lowGasTxs types.Transactions
|
lowGasTxs types.Transactions
|
||||||
localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion)
|
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
|
block *types.Block // the new block
|
||||||
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()),
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// 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 {
|
func (self *worker) pendingState() *state.StateDB {
|
||||||
self.currentMu.Lock()
|
self.currentMu.Lock()
|
||||||
defer self.currentMu.Unlock()
|
defer self.currentMu.Unlock()
|
||||||
|
|
||||||
return self.current.state
|
return self.current.state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) pendingBlock() *types.Block {
|
func (self *worker) pendingBlock() *types.Block {
|
||||||
self.currentMu.Lock()
|
self.currentMu.Lock()
|
||||||
defer self.currentMu.Unlock()
|
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
|
return self.current.block
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +200,7 @@ out:
|
|||||||
// Apply transaction to the pending state if we're not mining
|
// Apply transaction to the pending state if we're not mining
|
||||||
if atomic.LoadInt32(&self.mining) == 0 {
|
if atomic.LoadInt32(&self.mining) == 0 {
|
||||||
self.mu.Lock()
|
self.mu.Lock()
|
||||||
self.commitTransactions(types.Transactions{ev.Tx})
|
self.current.commitTransactions(types.Transactions{ev.Tx}, self.gasPrice, self.proc)
|
||||||
self.mu.Unlock()
|
self.mu.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,8 +253,8 @@ func (self *worker) wait() {
|
|||||||
jsonlogger.LogJson(&logger.EthMinerNewBlock{
|
jsonlogger.LogJson(&logger.EthMinerNewBlock{
|
||||||
BlockHash: block.Hash().Hex(),
|
BlockHash: block.Hash().Hex(),
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
ChainHeadHash: block.ParentHeaderHash.Hex(),
|
ChainHeadHash: block.ParentHash().Hex(),
|
||||||
BlockPrevHash: block.ParentHeaderHash.Hex(),
|
BlockPrevHash: block.ParentHash().Hex(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
self.commitNewWork()
|
self.commitNewWork()
|
||||||
@ -271,14 +265,12 @@ func (self *worker) wait() {
|
|||||||
|
|
||||||
func (self *worker) push() {
|
func (self *worker) push() {
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&self.mining) == 1 {
|
||||||
self.current.block.SetRoot(self.current.state.Root())
|
|
||||||
|
|
||||||
// push new work to agents
|
// push new work to agents
|
||||||
for _, agent := range self.agents {
|
for _, agent := range self.agents {
|
||||||
atomic.AddInt32(&self.atWork, 1)
|
atomic.AddInt32(&self.atWork, 1)
|
||||||
|
|
||||||
if agent.Work() != nil {
|
if agent.Work() != nil {
|
||||||
agent.Work() <- self.current.block.Copy()
|
agent.Work() <- self.current.block
|
||||||
} else {
|
} else {
|
||||||
common.Report(fmt.Sprintf("%v %T\n", agent, agent))
|
common.Report(fmt.Sprintf("%v %T\n", agent, agent))
|
||||||
}
|
}
|
||||||
@ -286,22 +278,20 @@ func (self *worker) push() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) makeCurrent() {
|
// makeCurrent creates a new environment for the current cycle.
|
||||||
block := self.chain.NewBlock(self.coinbase)
|
func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
|
||||||
parent := self.chain.GetBlock(block.ParentHash())
|
state := state.New(parent.Root(), self.eth.StateDb())
|
||||||
// TMP fix for build server ...
|
current := &environment{
|
||||||
if parent == nil {
|
state: state,
|
||||||
return
|
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)
|
// when 08 is processed ancestors contain 07 (quick block)
|
||||||
current := env(block, self.eth)
|
for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
||||||
for _, ancestor := range self.chain.GetAncestors(block, 7) {
|
|
||||||
for _, uncle := range ancestor.Uncles() {
|
for _, uncle := range ancestor.Uncles() {
|
||||||
current.family.Add(uncle.Hash())
|
current.family.Add(uncle.Hash())
|
||||||
}
|
}
|
||||||
@ -309,6 +299,7 @@ func (self *worker) makeCurrent() {
|
|||||||
current.ancestors.Add(ancestor.Hash())
|
current.ancestors.Add(ancestor.Hash())
|
||||||
}
|
}
|
||||||
accounts, _ := self.eth.AccountManager().Accounts()
|
accounts, _ := self.eth.AccountManager().Accounts()
|
||||||
|
|
||||||
// Keep track of transactions which return errors so they can be removed
|
// Keep track of transactions which return errors so they can be removed
|
||||||
current.remove = set.New()
|
current.remove = set.New()
|
||||||
current.tcount = 0
|
current.tcount = 0
|
||||||
@ -318,9 +309,6 @@ func (self *worker) makeCurrent() {
|
|||||||
if self.current != nil {
|
if self.current != nil {
|
||||||
current.localMinedBlocks = self.current.localMinedBlocks
|
current.localMinedBlocks = self.current.localMinedBlocks
|
||||||
}
|
}
|
||||||
|
|
||||||
current.coinbase.SetGasLimit(core.CalcGasLimit(parent))
|
|
||||||
|
|
||||||
self.current = current
|
self.current = current
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,13 +340,13 @@ func (self *worker) isBlockLocallyMined(deepBlockNum uint64) bool {
|
|||||||
|
|
||||||
//Does the block at {deepBlockNum} send earnings to my coinbase?
|
//Does the block at {deepBlockNum} send earnings to my coinbase?
|
||||||
var block = self.chain.GetBlockByNumber(deepBlockNum)
|
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) {
|
func (self *worker) logLocalMinedBlocks(previous *environment) {
|
||||||
if previous != nil && self.current.localMinedBlocks != nil {
|
if previous != nil && self.current.localMinedBlocks != nil {
|
||||||
nextBlockNum := self.current.block.Number().Uint64()
|
nextBlockNum := self.current.block.NumberU64()
|
||||||
for checkBlockNum := previous.block.Number().Uint64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
|
for checkBlockNum := previous.block.NumberU64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
|
||||||
inspectBlockNum := checkBlockNum - miningLogAtDepth
|
inspectBlockNum := checkBlockNum - miningLogAtDepth
|
||||||
if self.isBlockLocallyMined(inspectBlockNum) {
|
if self.isBlockLocallyMined(inspectBlockNum) {
|
||||||
glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, 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()
|
defer self.currentMu.Unlock()
|
||||||
|
|
||||||
tstart := time.Now()
|
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
|
previous := self.current
|
||||||
self.makeCurrent()
|
self.makeCurrent(parent, header)
|
||||||
current := self.current
|
current := self.current
|
||||||
|
|
||||||
|
// commit transactions for this run.
|
||||||
transactions := self.eth.TxPool().GetTransactions()
|
transactions := self.eth.TxPool().GetTransactions()
|
||||||
sort.Sort(types.TxByNonce{transactions})
|
sort.Sort(types.TxByNonce{transactions})
|
||||||
|
current.coinbase.SetGasLimit(header.GasLimit)
|
||||||
// commit transactions for this run
|
current.commitTransactions(transactions, self.gasPrice, self.proc)
|
||||||
self.commitTransactions(transactions)
|
|
||||||
self.eth.TxPool().RemoveTransactions(current.lowGasTxs)
|
self.eth.TxPool().RemoveTransactions(current.lowGasTxs)
|
||||||
|
|
||||||
|
// compute uncles for the new block.
|
||||||
var (
|
var (
|
||||||
uncles []*types.Header
|
uncles []*types.Header
|
||||||
badUncles []common.Hash
|
badUncles []common.Hash
|
||||||
@ -396,88 +401,76 @@ func (self *worker) commitNewWork() {
|
|||||||
if len(uncles) == 2 {
|
if len(uncles) == 2 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := self.commitUncle(uncle.Header()); err != nil {
|
if err := self.commitUncle(uncle.Header()); err != nil {
|
||||||
if glog.V(logger.Ridiculousness) {
|
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).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
|
||||||
glog.V(logger.Detail).Infoln(uncle)
|
glog.V(logger.Detail).Infoln(uncle)
|
||||||
}
|
}
|
||||||
|
|
||||||
badUncles = append(badUncles, hash)
|
badUncles = append(badUncles, hash)
|
||||||
} else {
|
} else {
|
||||||
glog.V(logger.Debug).Infof("commiting %x as uncle\n", hash[:4])
|
glog.V(logger.Debug).Infof("commiting %x as uncle\n", hash[:4])
|
||||||
uncles = append(uncles, uncle.Header())
|
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 {
|
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))
|
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)
|
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()
|
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 {
|
func (self *worker) commitUncle(uncle *types.Header) error {
|
||||||
if self.current.uncles.Has(uncle.Hash()) {
|
hash := uncle.Hash()
|
||||||
// Error not unique
|
if self.current.uncles.Has(hash) {
|
||||||
return core.UncleError("Uncle not unique")
|
return core.UncleError("Uncle not unique")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.current.ancestors.Has(uncle.ParentHash) {
|
if !self.current.ancestors.Has(uncle.ParentHash) {
|
||||||
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||||
}
|
}
|
||||||
|
if self.current.family.Has(hash) {
|
||||||
if self.current.family.Has(uncle.Hash()) {
|
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash))
|
||||||
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", uncle.Hash()))
|
|
||||||
}
|
}
|
||||||
self.current.uncles.Add(uncle.Hash())
|
self.current.uncles.Add(uncle.Hash())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) commitTransactions(transactions types.Transactions) {
|
func (env *environment) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
|
||||||
current := self.current
|
|
||||||
|
|
||||||
for _, tx := range transactions {
|
for _, tx := range transactions {
|
||||||
// We can skip err. It has already been validated in the tx pool
|
// We can skip err. It has already been validated in the tx pool
|
||||||
from, _ := tx.From()
|
from, _ := tx.From()
|
||||||
|
|
||||||
// Check if it falls within margin. Txs from owned accounts are always processed.
|
// 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
|
// ignore the transaction and transactor. We ignore the transactor
|
||||||
// because nonce will fail after ignoring this transaction so there's
|
// because nonce will fail after ignoring this transaction so there's
|
||||||
// no point
|
// 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
|
// 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
|
// the low gas tx set. This will also remove the tx and all sequential transaction
|
||||||
// from this transactor
|
// 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
|
// add tx to the low gas set. This will be removed at the end of the run
|
||||||
// owned accounts are ignored
|
// owned accounts are ignored
|
||||||
if !current.ownedAccounts.Has(from) {
|
if !env.ownedAccounts.Has(from) {
|
||||||
current.lowGasTxs = append(current.lowGasTxs, tx)
|
env.lowGasTxs = append(env.lowGasTxs, tx)
|
||||||
}
|
}
|
||||||
continue
|
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
|
// 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.
|
// will throw a nonce error because the previous transaction hasn't been processed.
|
||||||
// Therefor we need to ignore any transaction after the ignored one.
|
// Therefor we need to ignore any transaction after the ignored one.
|
||||||
if current.ignoredTransactors.Has(from) {
|
if env.ignoredTransactors.Has(from) {
|
||||||
continue
|
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 {
|
switch {
|
||||||
case core.IsNonceErr(err) || core.IsInvalidTxErr(err):
|
case core.IsNonceErr(err) || core.IsInvalidTxErr(err):
|
||||||
current.remove.Add(tx.Hash())
|
env.remove.Add(tx.Hash())
|
||||||
|
|
||||||
if glog.V(logger.Detail) {
|
if glog.V(logger.Detail) {
|
||||||
glog.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
|
glog.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
|
||||||
}
|
}
|
||||||
case state.IsGasLimitErr(err):
|
case state.IsGasLimitErr(err):
|
||||||
from, _ := tx.From()
|
|
||||||
// ignore the transactor so no nonce errors will be thrown for this account
|
// 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.
|
// 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])
|
glog.V(logger.Detail).Infof("Gas limit reached for (%x) in this block. Continue to try smaller txs\n", from[:4])
|
||||||
default:
|
default:
|
||||||
current.tcount++
|
env.tcount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current.block.Header().GasUsed = self.current.totalUsedGas
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) commitTransaction(tx *types.Transaction) error {
|
func (env *environment) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor) error {
|
||||||
snap := self.current.state.Copy()
|
snap := env.state.Copy()
|
||||||
receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true)
|
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)) {
|
if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) {
|
||||||
self.current.state.Set(snap)
|
env.state.Set(snap)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
env.txs = append(env.txs, tx)
|
||||||
self.current.block.AddTransaction(tx)
|
env.receipts = append(env.receipts, receipt)
|
||||||
self.current.block.AddReceipt(receipt)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
|
|||||||
if b.BlockHeader == nil {
|
if b.BlockHeader == nil {
|
||||||
continue // OK - block is supposed to be invalid, continue with next block
|
continue // OK - block is supposed to be invalid, continue with next block
|
||||||
} else {
|
} 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:
|
// RLP decoding worked, try to insert into chain:
|
||||||
@ -254,7 +254,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
|
|||||||
if b.BlockHeader == nil {
|
if b.BlockHeader == nil {
|
||||||
continue // OK - block is supposed to be invalid, continue with next block
|
continue // OK - block is supposed to be invalid, continue with next block
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("Block insertion into chain failed: ", err)
|
return fmt.Errorf("Block insertion into chain failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if b.BlockHeader == nil {
|
if b.BlockHeader == nil {
|
||||||
@ -262,7 +262,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
|
|||||||
}
|
}
|
||||||
err = t.validateBlockHeader(b.BlockHeader, cb.Header())
|
err = t.validateBlockHeader(b.BlockHeader, cb.Header())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Block header validation failed: ", err)
|
return fmt.Errorf("Block header validation failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -286,7 +286,7 @@ func (s *BlockTest) validateBlockHeader(h *btHeader, h2 *types.Header) error {
|
|||||||
|
|
||||||
expectedNonce := mustConvertBytes(h.Nonce)
|
expectedNonce := mustConvertBytes(h.Nonce)
|
||||||
if !bytes.Equal(expectedNonce, h2.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)
|
expectedNumber := mustConvertBigInt(h.Number, 16)
|
||||||
@ -423,9 +423,8 @@ func mustConvertHeader(in btHeader) *types.Header {
|
|||||||
GasLimit: mustConvertBigInt(in.GasLimit, 16),
|
GasLimit: mustConvertBigInt(in.GasLimit, 16),
|
||||||
Difficulty: mustConvertBigInt(in.Difficulty, 16),
|
Difficulty: mustConvertBigInt(in.Difficulty, 16),
|
||||||
Time: mustConvertUint(in.Timestamp, 16),
|
Time: mustConvertUint(in.Timestamp, 16),
|
||||||
|
Nonce: types.EncodeNonce(mustConvertUint(in.Nonce, 16)),
|
||||||
}
|
}
|
||||||
// XXX cheats? :-)
|
|
||||||
header.SetNonce(mustConvertUint(in.Nonce, 16))
|
|
||||||
return header
|
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)
|
// - could be removed in favour of mining on testdag (natspec e2e + networking)
|
||||||
// + filters
|
// + filters
|
||||||
func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, txc uint64) (uint64, *XEth) {
|
func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, txc uint64) (uint64, *XEth) {
|
||||||
|
chain := self.backend.ChainManager()
|
||||||
block := self.backend.ChainManager().NewBlock(address)
|
header := chain.CurrentBlock().Header()
|
||||||
coinbase := statedb.GetStateObject(address)
|
coinbase := statedb.GetStateObject(address)
|
||||||
coinbase.SetGasLimit(big.NewInt(10000000))
|
coinbase.SetGasLimit(big.NewInt(10000000))
|
||||||
txs := self.backend.TxPool().GetQueuedTransactions()
|
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 i := 0; i < len(txs); i++ {
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
if tx.Nonce() == txc {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -845,8 +845,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
|
|||||||
msg.gasPrice = self.DefaultGasPrice()
|
msg.gasPrice = self.DefaultGasPrice()
|
||||||
}
|
}
|
||||||
|
|
||||||
block := self.CurrentBlock()
|
header := self.CurrentBlock().Header()
|
||||||
vmenv := core.NewEnv(statedb, self.backend.ChainManager(), msg, block)
|
vmenv := core.NewEnv(statedb, self.backend.ChainManager(), msg, header)
|
||||||
|
|
||||||
res, gas, err := core.ApplyMessage(vmenv, msg, from)
|
res, gas, err := core.ApplyMessage(vmenv, msg, from)
|
||||||
return common.ToHex(res), gas.String(), err
|
return common.ToHex(res), gas.String(), err
|
||||||
|
Loading…
Reference in New Issue
Block a user