aboutsummaryrefslogtreecommitdiff
path: root/consensus/dummy
diff options
context:
space:
mode:
Diffstat (limited to 'consensus/dummy')
-rw-r--r--consensus/dummy/consensus.go429
1 files changed, 249 insertions, 180 deletions
diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go
index 0086581..9f3791a 100644
--- a/consensus/dummy/consensus.go
+++ b/consensus/dummy/consensus.go
@@ -1,243 +1,312 @@
package dummy
import (
- "fmt"
- "time"
- "errors"
- "runtime"
- "math/big"
- "golang.org/x/crypto/sha3"
-
- "github.com/ethereum/go-ethereum/consensus"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/params"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/rpc"
+ "errors"
+ "fmt"
+ "golang.org/x/crypto/sha3"
+ "math/big"
+ "runtime"
+ "time"
+
+ mapset "github.com/deckarep/golang-set"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus"
+ "github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/rpc"
)
type ConsensusCallbacks struct {
- OnSeal func(*types.Block)
+ OnSeal func(*types.Block) error
+ OnAPIs func(consensus.ChainReader) []rpc.API
+ OnFinalize func(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header)
+ OnFinalizeAndAssemble func(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt)
}
type DummyEngine struct {
- cb *ConsensusCallbacks
+ cb *ConsensusCallbacks
}
func NewDummyEngine(cb *ConsensusCallbacks) *DummyEngine {
- return &DummyEngine { cb: cb }
+ return &DummyEngine{cb: cb}
}
var (
- allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks
+ allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks
)
var (
- errZeroBlockTime = errors.New("timestamp equals parent's")
+ maxUncles = 2 // Maximum number of uncles allowed in a single block
+
+ errTooManyUncles = errors.New("too many uncles")
+ errZeroBlockTime = errors.New("timestamp equals parent's")
+ errDuplicateUncle = errors.New("duplicate uncle")
+ errUncleIsAncestor = errors.New("uncle is ancestor")
+ errDanglingUncle = errors.New("uncle's parent is not ancestor")
)
// modified from consensus.go
func (self *DummyEngine) verifyHeader(chain consensus.ChainReader, header, parent *types.Header, uncle bool, seal bool) error {
- // Ensure that the header's extra-data section is of a reasonable size
- if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
- return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
- }
- // Verify the header's timestamp
- if !uncle {
- if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) {
- return consensus.ErrFutureBlock
- }
- }
- if header.Time <= parent.Time {
- return errZeroBlockTime
- }
- // Verify that the gas limit is <= 2^63-1
- cap := uint64(0x7fffffffffffffff)
- if header.GasLimit > cap {
- return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
- }
- // Verify that the gasUsed is <= gasLimit
- if header.GasUsed > header.GasLimit {
- return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
- }
-
- // Verify that the gas limit remains within allowed bounds
- diff := int64(parent.GasLimit) - int64(header.GasLimit)
- if diff < 0 {
- diff *= -1
- }
- limit := parent.GasLimit / params.GasLimitBoundDivisor
-
- if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
- return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
- }
- // Verify that the block number is parent's +1
- if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
- return consensus.ErrInvalidNumber
- }
- // Verify the engine specific seal securing the block
- if seal {
- if err := self.VerifySeal(chain, header); err != nil {
- return err
- }
- }
- return nil
+ // Ensure that the header's extra-data section is of a reasonable size
+ if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
+ return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
+ }
+ // Verify the header's timestamp
+ if !uncle {
+ if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) {
+ return consensus.ErrFutureBlock
+ }
+ }
+ if header.Time <= parent.Time {
+ return errZeroBlockTime
+ }
+ // Verify that the gas limit is <= 2^63-1
+ cap := uint64(0x7fffffffffffffff)
+ if header.GasLimit > cap {
+ return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
+ }
+ // Verify that the gasUsed is <= gasLimit
+ if header.GasUsed > header.GasLimit {
+ return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
+ }
+
+ // Verify that the gas limit remains within allowed bounds
+ diff := int64(parent.GasLimit) - int64(header.GasLimit)
+ if diff < 0 {
+ diff *= -1
+ }
+ limit := parent.GasLimit / params.GasLimitBoundDivisor
+
+ if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
+ return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
+ }
+ // Verify that the block number is parent's +1
+ if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
+ return consensus.ErrInvalidNumber
+ }
+ // Verify the engine specific seal securing the block
+ if seal {
+ if err := self.VerifySeal(chain, header); err != nil {
+ return err
+ }
+ }
+ return nil
}
func (self *DummyEngine) verifyHeaderWorker(chain consensus.ChainReader, headers []*types.Header, seals []bool, index int) error {
- var parent *types.Header
- if index == 0 {
- parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1)
- } else if headers[index-1].Hash() == headers[index].ParentHash {
- parent = headers[index-1]
- }
- if parent == nil {
- return consensus.ErrUnknownAncestor
- }
- if chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()) != nil {
- return nil // known block
- }
- return self.verifyHeader(chain, headers[index], parent, false, seals[index])
+ var parent *types.Header
+ if index == 0 {
+ parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1)
+ } else if headers[index-1].Hash() == headers[index].ParentHash {
+ parent = headers[index-1]
+ }
+ if parent == nil {
+ return consensus.ErrUnknownAncestor
+ }
+ if chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()) != nil {
+ return nil // known block
+ }
+ return self.verifyHeader(chain, headers[index], parent, false, seals[index])
}
func (self *DummyEngine) Author(header *types.Header) (common.Address, error) {
- return header.Coinbase, nil
+ return header.Coinbase, nil
}
func (self *DummyEngine) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
- // Short circuit if the header is known, or it's parent not
- number := header.Number.Uint64()
- if chain.GetHeader(header.Hash(), number) != nil {
- return nil
- }
- parent := chain.GetHeader(header.ParentHash, number-1)
- if parent == nil {
- return consensus.ErrUnknownAncestor
- }
- // Sanity checks passed, do a proper verification
- return self.verifyHeader(chain, header, parent, false, seal)
+ // Short circuit if the header is known, or it's parent not
+ number := header.Number.Uint64()
+ if chain.GetHeader(header.Hash(), number) != nil {
+ return nil
+ }
+ parent := chain.GetHeader(header.ParentHash, number-1)
+ if parent == nil {
+ return consensus.ErrUnknownAncestor
+ }
+ // Sanity checks passed, do a proper verification
+ return self.verifyHeader(chain, header, parent, false, seal)
}
func (self *DummyEngine) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
- // Spawn as many workers as allowed threads
- workers := runtime.GOMAXPROCS(0)
- if len(headers) < workers {
- workers = len(headers)
- }
-
- // Create a task channel and spawn the verifiers
- var (
- inputs = make(chan int)
- done = make(chan int, workers)
- errors = make([]error, len(headers))
- abort = make(chan struct{})
- )
- for i := 0; i < workers; i++ {
- go func() {
- for index := range inputs {
- errors[index] = self.verifyHeaderWorker(chain, headers, seals, index)
- done <- index
- }
- }()
- }
-
- errorsOut := make(chan error, len(headers))
- go func() {
- defer close(inputs)
- var (
- in, out = 0, 0
- checked = make([]bool, len(headers))
- inputs = inputs
- )
- for {
- select {
- case inputs <- in:
- if in++; in == len(headers) {
- // Reached end of headers. Stop sending to workers.
- inputs = nil
- }
- case index := <-done:
- for checked[index] = true; checked[out]; out++ {
- errorsOut <- errors[out]
- if out == len(headers)-1 {
- return
- }
- }
- case <-abort:
- return
- }
- }
- }()
- return abort, errorsOut
+ // Spawn as many workers as allowed threads
+ workers := runtime.GOMAXPROCS(0)
+ if len(headers) < workers {
+ workers = len(headers)
+ }
+
+ // Create a task channel and spawn the verifiers
+ var (
+ inputs = make(chan int)
+ done = make(chan int, workers)
+ errors = make([]error, len(headers))
+ abort = make(chan struct{})
+ )
+ for i := 0; i < workers; i++ {
+ go func() {
+ for index := range inputs {
+ errors[index] = self.verifyHeaderWorker(chain, headers, seals, index)
+ done <- index
+ }
+ }()
+ }
+
+ errorsOut := make(chan error, len(headers))
+ go func() {
+ defer close(inputs)
+ var (
+ in, out = 0, 0
+ checked = make([]bool, len(headers))
+ inputs = inputs
+ )
+ for {
+ select {
+ case inputs <- in:
+ if in++; in == len(headers) {
+ // Reached end of headers. Stop sending to workers.
+ inputs = nil
+ }
+ case index := <-done:
+ for checked[index] = true; checked[out]; out++ {
+ errorsOut <- errors[out]
+ if out == len(headers)-1 {
+ return
+ }
+ }
+ case <-abort:
+ return
+ }
+ }
+ }()
+ return abort, errorsOut
}
func (self *DummyEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
- return nil
+ // Verify that there are at most 2 uncles included in this block
+ if len(block.Uncles()) > maxUncles {
+ return errTooManyUncles
+ }
+ if len(block.Uncles()) == 0 {
+ return nil
+ }
+ // Gather the set of past uncles and ancestors
+ uncles, ancestors := mapset.NewSet(), make(map[common.Hash]*types.Header)
+
+ number, parent := block.NumberU64()-1, block.ParentHash()
+ for i := 0; i < 7; i++ {
+ ancestor := chain.GetBlock(parent, number)
+ if ancestor == nil {
+ break
+ }
+ ancestors[ancestor.Hash()] = ancestor.Header()
+ for _, uncle := range ancestor.Uncles() {
+ uncles.Add(uncle.Hash())
+ }
+ parent, number = ancestor.ParentHash(), number-1
+ }
+ ancestors[block.Hash()] = block.Header()
+ uncles.Add(block.Hash())
+
+ // Verify each of the uncles that it's recent, but not an ancestor
+ for _, uncle := range block.Uncles() {
+ // Make sure every uncle is rewarded only once
+ hash := uncle.Hash()
+ if uncles.Contains(hash) {
+ return errDuplicateUncle
+ }
+ uncles.Add(hash)
+
+ // Make sure the uncle has a valid ancestry
+ if ancestors[hash] != nil {
+ return errUncleIsAncestor
+ }
+ if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == block.ParentHash() {
+ return errDanglingUncle
+ }
+ if err := self.verifyHeader(chain, uncle, ancestors[uncle.ParentHash], true, true); err != nil {
+ return err
+ }
+ }
+ return nil
}
func (self *DummyEngine) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
- return nil
+ return nil
}
func (self *DummyEngine) Prepare(chain consensus.ChainReader, header *types.Header) error {
- header.Difficulty = big.NewInt(1)
- return nil
+ header.Difficulty = big.NewInt(1)
+ return nil
}
-func (self *DummyEngine) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
-uncles []*types.Header) {
- // commit the final state root
- header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
+func (self *DummyEngine) Finalize(
+ chain consensus.ChainReader, header *types.Header,
+ state *state.StateDB, txs []*types.Transaction,
+ uncles []*types.Header) {
+ if self.cb.OnFinalize != nil {
+ self.cb.OnFinalize(chain, header, state, txs, uncles)
+ }
+ // commit the final state root
+ header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
}
func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
-uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
- // commit the final state root
- header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
+ uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
+ if self.cb.OnFinalizeAndAssemble != nil {
+ self.cb.OnFinalizeAndAssemble(chain, header, state, txs, uncles, receipts)
+ }
+ // commit the final state root
+ header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
- // Header seems complete, assemble into a block and return
- return types.NewBlock(header, txs, uncles, receipts), nil
+ // Header seems complete, assemble into a block and return
+ return types.NewBlock(header, txs, uncles, receipts), nil
}
-func (self *DummyEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
- if self.cb.OnSeal != nil {
- self.cb.OnSeal(block)
- }
- results <- block
- return nil
+func (self *DummyEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) (err error) {
+ if self.cb.OnSeal != nil {
+ err = self.cb.OnSeal(block)
+ } else {
+ err = nil
+ }
+ results <- block
+ return
}
func (self *DummyEngine) SealHash(header *types.Header) (hash common.Hash) {
- hasher := sha3.NewLegacyKeccak256()
-
- rlp.Encode(hasher, []interface{}{
- header.ParentHash,
- header.UncleHash,
- header.Coinbase,
- header.Root,
- header.TxHash,
- header.ReceiptHash,
- header.Bloom,
- header.Difficulty,
- header.Number,
- header.GasLimit,
- header.GasUsed,
- header.Time,
- header.Extra,
- })
- hasher.Sum(hash[:0])
- return hash
+ hasher := sha3.NewLegacyKeccak256()
+
+ rlp.Encode(hasher, []interface{}{
+ header.ParentHash,
+ header.UncleHash,
+ header.Coinbase,
+ header.Root,
+ header.TxHash,
+ header.ReceiptHash,
+ header.Bloom,
+ header.Difficulty,
+ header.Number,
+ header.GasLimit,
+ header.GasUsed,
+ header.Time,
+ header.Extra,
+ })
+ hasher.Sum(hash[:0])
+ return hash
}
func (self *DummyEngine) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
- return big.NewInt(1)
+ return big.NewInt(1)
}
-func (self *DummyEngine) APIs(chain consensus.ChainReader) []rpc.API {
- return nil
+func (self *DummyEngine) APIs(chain consensus.ChainReader) (res []rpc.API) {
+ res = nil
+ if self.cb.OnAPIs != nil {
+ res = self.cb.OnAPIs(chain)
+ }
+ return
}
func (self *DummyEngine) Close() error {
- return nil
+ return nil
}