mirror of
https://gitlab.com/pulsechaincom/go-pulse.git
synced 2024-12-22 03:30:35 +00:00
Add support for syncing pre-fork blocks
This commit is contained in:
parent
c9e7be708b
commit
40db66c21c
@ -80,18 +80,20 @@ func (beacon *Beacon) Author(header *types.Header) (common.Address, error) {
|
|||||||
|
|
||||||
// VerifyHeader checks whether a header conforms to the consensus rules of the
|
// VerifyHeader checks whether a header conforms to the consensus rules of the
|
||||||
// stock Ethereum consensus engine.
|
// stock Ethereum consensus engine.
|
||||||
func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
|
func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parent *types.Header) error {
|
||||||
reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1)
|
reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !reached {
|
if !reached {
|
||||||
return beacon.ethone.VerifyHeader(chain, header)
|
return beacon.ethone.VerifyHeader(chain, header, parent)
|
||||||
}
|
}
|
||||||
// Short circuit if the parent is not known
|
// Short circuit if the parent is not known
|
||||||
parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
|
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return consensus.ErrUnknownAncestor
|
parent = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
|
||||||
|
if parent == nil {
|
||||||
|
return consensus.ErrUnknownAncestor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Sanity checks passed, do a proper verification
|
// Sanity checks passed, do a proper verification
|
||||||
return beacon.verifyHeader(chain, header, parent)
|
return beacon.verifyHeader(chain, header, parent)
|
||||||
@ -128,21 +130,16 @@ func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []
|
|||||||
var (
|
var (
|
||||||
preHeaders = headers
|
preHeaders = headers
|
||||||
postHeaders []*types.Header
|
postHeaders []*types.Header
|
||||||
td = new(big.Int).Set(ptd)
|
|
||||||
tdPassed bool
|
|
||||||
)
|
)
|
||||||
for i, header := range headers {
|
for i, header := range headers {
|
||||||
if tdPassed {
|
// PulseChain Special Case:
|
||||||
|
// Partition based on header difficulty (IsPoSHeader) instead of TTD being reached
|
||||||
|
// so we can properly handle ETH Beacon blocks below the increased PulseChain TTD.
|
||||||
|
if beacon.IsPoSHeader(header) {
|
||||||
preHeaders = headers[:i]
|
preHeaders = headers[:i]
|
||||||
postHeaders = headers[i:]
|
postHeaders = headers[i:]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
td = td.Add(td, header.Difficulty)
|
|
||||||
if td.Cmp(ttd) >= 0 {
|
|
||||||
// This is the last PoW header, it still belongs to
|
|
||||||
// the preHeaders, so we cannot split+break yet.
|
|
||||||
tdPassed = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return preHeaders, postHeaders, nil
|
return preHeaders, postHeaders, nil
|
||||||
}
|
}
|
||||||
@ -151,31 +148,73 @@ func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []
|
|||||||
// concurrently. The method returns a quit channel to abort the operations and
|
// concurrently. The method returns a quit channel to abort the operations and
|
||||||
// a results channel to retrieve the async verifications.
|
// a results channel to retrieve the async verifications.
|
||||||
// VerifyHeaders expect the headers to be ordered and continuous.
|
// VerifyHeaders expect the headers to be ordered and continuous.
|
||||||
|
//
|
||||||
|
// Normal Cases:
|
||||||
|
// 1. x * POW blocks
|
||||||
|
// 2. x * POS blocks
|
||||||
|
// 3. x * POW blocks => y * POS blocks
|
||||||
|
//
|
||||||
|
// Special Cases for PulseChain:
|
||||||
|
// 4. x * POS blocks[eth] => POW fork block[pls]
|
||||||
|
// 5. x * POS blocks[eth] => POW fork block[pls] => y * POS blocks[pls]
|
||||||
func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) {
|
func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) {
|
||||||
preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers)
|
preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make(chan struct{}), errOut(len(headers), err)
|
return make(chan struct{}), errOut(len(headers), err)
|
||||||
}
|
}
|
||||||
|
// Case 1
|
||||||
if len(postHeaders) == 0 {
|
if len(postHeaders) == 0 {
|
||||||
return beacon.ethone.VerifyHeaders(chain, headers)
|
return beacon.ethone.VerifyHeaders(chain, headers)
|
||||||
}
|
}
|
||||||
if len(preHeaders) == 0 {
|
chainCfg := chain.Config()
|
||||||
|
primordialPulseIndex := 0
|
||||||
|
if chainCfg.PrimordialPulseAhead(postHeaders[0].Number) && !chainCfg.PrimordialPulseAhead(postHeaders[len(postHeaders)-1].Number) {
|
||||||
|
primordialPulseIndex = int(new(big.Int).Sub(chainCfg.PrimordialPulseBlock, postHeaders[0].Number).Uint64())
|
||||||
|
}
|
||||||
|
// Case 2
|
||||||
|
if len(preHeaders) == 0 && primordialPulseIndex == 0 {
|
||||||
return beacon.verifyHeaders(chain, headers, nil)
|
return beacon.verifyHeaders(chain, headers, nil)
|
||||||
}
|
}
|
||||||
// The transition point exists in the middle, separate the headers
|
// The transition point exists in the middle, separate the headers
|
||||||
// into two batches and apply different verification rules for them.
|
// into batches and apply different verification rules for them.
|
||||||
var (
|
var (
|
||||||
abort = make(chan struct{})
|
abort = make(chan struct{})
|
||||||
results = make(chan error, len(headers))
|
results = make(chan error, len(headers))
|
||||||
)
|
)
|
||||||
go func() {
|
go func() {
|
||||||
var (
|
var (
|
||||||
old, new, out = 0, len(preHeaders), 0
|
oldIdx, out = 0, 0
|
||||||
errors = make([]error, len(headers))
|
errors = make([]error, len(headers))
|
||||||
done = make([]bool, len(headers))
|
done = make([]bool, len(headers))
|
||||||
oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders)
|
oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders)
|
||||||
newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1])
|
lastPowHeader *types.Header
|
||||||
|
pulseChainForkHeader *types.Header
|
||||||
|
preforkPosIdx = len(preHeaders)
|
||||||
|
preforkPosHeaders = postHeaders
|
||||||
|
postforkPosIdx = len(headers)
|
||||||
|
postforkPosHeaders = []*types.Header{}
|
||||||
)
|
)
|
||||||
|
// Case 3
|
||||||
|
if len(preHeaders) > 0 {
|
||||||
|
lastPowHeader = preHeaders[len(preHeaders)-1]
|
||||||
|
}
|
||||||
|
// Handle fork partitioning and verification for cases 4 and 5
|
||||||
|
if primordialPulseIndex > 0 {
|
||||||
|
preforkPosHeaders = postHeaders[:primordialPulseIndex]
|
||||||
|
pulseChainForkHeader = postHeaders[primordialPulseIndex]
|
||||||
|
|
||||||
|
// Verify the fork block
|
||||||
|
forkBlockResult := beacon.ethone.VerifyHeader(chain, pulseChainForkHeader, postHeaders[primordialPulseIndex-1])
|
||||||
|
forkBlockIdx := preforkPosIdx + len(preforkPosHeaders)
|
||||||
|
errors[forkBlockIdx], done[forkBlockIdx] = forkBlockResult, true
|
||||||
|
|
||||||
|
// Can be empty in case 4
|
||||||
|
postforkPosHeaders = postHeaders[primordialPulseIndex+1:]
|
||||||
|
postforkPosIdx = forkBlockIdx + 1
|
||||||
|
}
|
||||||
|
preforkPosDone, preforkPosResult := beacon.verifyHeaders(chain, preforkPosHeaders, lastPowHeader)
|
||||||
|
postforkPosDone, postforkPosResult := beacon.verifyHeaders(chain, postforkPosHeaders, pulseChainForkHeader)
|
||||||
|
|
||||||
// Collect the results
|
// Collect the results
|
||||||
for {
|
for {
|
||||||
for ; done[out]; out++ {
|
for ; done[out]; out++ {
|
||||||
@ -186,16 +225,20 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [
|
|||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case err := <-oldResult:
|
case err := <-oldResult:
|
||||||
if !done[old] { // skip TTD-verified failures
|
if !done[oldIdx] { // skip TTD-verified failures
|
||||||
errors[old], done[old] = err, true
|
errors[oldIdx], done[oldIdx] = err, true
|
||||||
}
|
}
|
||||||
old++
|
oldIdx++
|
||||||
case err := <-newResult:
|
case err := <-preforkPosResult:
|
||||||
errors[new], done[new] = err, true
|
errors[preforkPosIdx], done[preforkPosIdx] = err, true
|
||||||
new++
|
preforkPosIdx++
|
||||||
|
case err := <-postforkPosResult:
|
||||||
|
errors[postforkPosIdx], done[postforkPosIdx] = err, true
|
||||||
|
postforkPosIdx++
|
||||||
case <-abort:
|
case <-abort:
|
||||||
close(oldDone)
|
close(oldDone)
|
||||||
close(newDone)
|
close(preforkPosDone)
|
||||||
|
close(postforkPosDone)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,8 +216,12 @@ func (c *Clique) Author(header *types.Header) (common.Address, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifyHeader checks whether a header conforms to the consensus rules.
|
// VerifyHeader checks whether a header conforms to the consensus rules.
|
||||||
func (c *Clique) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
|
func (c *Clique) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parent *types.Header) error {
|
||||||
return c.verifyHeader(chain, header, nil)
|
var parentHeaders []*types.Header
|
||||||
|
if parent != nil {
|
||||||
|
parentHeaders = []*types.Header{parent}
|
||||||
|
}
|
||||||
|
return c.verifyHeader(chain, header, parentHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
|
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
|
||||||
|
@ -67,7 +67,7 @@ type Engine interface {
|
|||||||
|
|
||||||
// VerifyHeader checks whether a header conforms to the consensus rules of a
|
// VerifyHeader checks whether a header conforms to the consensus rules of a
|
||||||
// given engine.
|
// given engine.
|
||||||
VerifyHeader(chain ChainHeaderReader, header *types.Header) error
|
VerifyHeader(chain ChainHeaderReader, header *types.Header, parent *types.Header) error
|
||||||
|
|
||||||
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
|
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
|
||||||
// concurrently. The method returns a quit channel to abort the operations and
|
// concurrently. The method returns a quit channel to abort the operations and
|
||||||
|
@ -100,15 +100,17 @@ func (ethash *Ethash) Author(header *types.Header) (common.Address, error) {
|
|||||||
|
|
||||||
// VerifyHeader checks whether a header conforms to the consensus rules of the
|
// VerifyHeader checks whether a header conforms to the consensus rules of the
|
||||||
// stock Ethereum ethash engine.
|
// stock Ethereum ethash engine.
|
||||||
func (ethash *Ethash) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
|
func (ethash *Ethash) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parent *types.Header) error {
|
||||||
// Short circuit if the header is known, or its parent not
|
// Short circuit if the header is known, or its parent not
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
if chain.GetHeader(header.Hash(), number) != nil {
|
if chain.GetHeader(header.Hash(), number) != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
parent := chain.GetHeader(header.ParentHash, number-1)
|
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return consensus.ErrUnknownAncestor
|
parent = chain.GetHeader(header.ParentHash, number-1)
|
||||||
|
if parent == nil {
|
||||||
|
return consensus.ErrUnknownAncestor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Sanity checks passed, do a proper verification
|
// Sanity checks passed, do a proper verification
|
||||||
return ethash.verifyHeader(chain, header, parent, false, time.Now().Unix())
|
return ethash.verifyHeader(chain, header, parent, false, time.Now().Unix())
|
||||||
|
@ -410,7 +410,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
// The first thing the node will do is reconstruct the verification data for
|
// The first thing the node will do is reconstruct the verification data for
|
||||||
// the head block (ethash cache or clique voting snapshot). Might as well do
|
// the head block (ethash cache or clique voting snapshot). Might as well do
|
||||||
// it in advance.
|
// it in advance.
|
||||||
bc.engine.VerifyHeader(bc, bc.CurrentHeader())
|
bc.engine.VerifyHeader(bc, bc.CurrentHeader(), nil)
|
||||||
|
|
||||||
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
|
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
|
||||||
for hash := range BadHashes {
|
for hash := range BadHashes {
|
||||||
|
@ -149,7 +149,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara
|
|||||||
func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||||
for _, block := range chain {
|
for _, block := range chain {
|
||||||
// Try and process the block
|
// Try and process the block
|
||||||
err := blockchain.engine.VerifyHeader(blockchain, block.Header())
|
err := blockchain.engine.VerifyHeader(blockchain, block.Header(), nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = blockchain.validator.ValidateBody(block)
|
err = blockchain.validator.ValidateBody(block)
|
||||||
}
|
}
|
||||||
@ -188,7 +188,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
|||||||
func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error {
|
func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error {
|
||||||
for _, header := range chain {
|
for _, header := range chain {
|
||||||
// Try and validate the header
|
// Try and validate the header
|
||||||
if err := blockchain.engine.VerifyHeader(blockchain, header); err != nil {
|
if err := blockchain.engine.VerifyHeader(blockchain, header, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Manually insert the header into the database, but don't reorganise (allows subsequent testing)
|
// Manually insert the header into the database, but don't reorganise (allows subsequent testing)
|
||||||
|
@ -108,6 +108,10 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
|
|||||||
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
||||||
}
|
}
|
||||||
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
|
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
|
||||||
|
} else if f.chain.Config().PrimordialPulseAhead(extern.Number) {
|
||||||
|
// Pre-fork ethereum mainnet pos blocks have a difficulty of 0.
|
||||||
|
// These blocks should be accepted onto the chain head.
|
||||||
|
reorg = true
|
||||||
}
|
}
|
||||||
return reorg, nil
|
return reorg, nil
|
||||||
}
|
}
|
||||||
|
@ -39,15 +39,22 @@ type sigCache struct {
|
|||||||
// MakeSigner returns a Signer based on the given chain config and block number.
|
// MakeSigner returns a Signer based on the given chain config and block number.
|
||||||
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer {
|
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer {
|
||||||
var signer Signer
|
var signer Signer
|
||||||
|
|
||||||
|
chainID := config.ChainID
|
||||||
|
if config.PrimordialPulseAhead(blockNumber) {
|
||||||
|
// Use ethereum mainnet chainid for pre-fork transactions
|
||||||
|
chainID = big.NewInt(1)
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.IsCancun(blockNumber, blockTime):
|
case config.IsCancun(blockNumber, blockTime):
|
||||||
signer = NewCancunSigner(config.ChainID)
|
signer = NewCancunSigner(config.ChainID)
|
||||||
case config.IsLondon(blockNumber):
|
case config.IsLondon(blockNumber):
|
||||||
signer = NewLondonSigner(config.ChainID)
|
signer = NewLondonSigner(chainID)
|
||||||
case config.IsBerlin(blockNumber):
|
case config.IsBerlin(blockNumber):
|
||||||
signer = NewEIP2930Signer(config.ChainID)
|
signer = NewEIP2930Signer(chainID)
|
||||||
case config.IsEIP155(blockNumber):
|
case config.IsEIP155(blockNumber):
|
||||||
signer = NewEIP155Signer(config.ChainID)
|
signer = NewEIP155Signer(chainID)
|
||||||
case config.IsHomestead(blockNumber):
|
case config.IsHomestead(blockNumber):
|
||||||
signer = HomesteadSigner{}
|
signer = HomesteadSigner{}
|
||||||
default:
|
default:
|
||||||
|
@ -137,13 +137,25 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
|
|||||||
blockCtx.BlobBaseFee = new(big.Int)
|
blockCtx.BlobBaseFee = new(big.Int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FlexChainConfig allows for processing prefork transactions on PulseChain
|
||||||
|
flexChainConfig := chainConfig
|
||||||
|
if chainConfig.PrimordialPulseAhead(blockCtx.BlockNumber) {
|
||||||
|
// Create a shallow of chainConfig struct and set to ethereum mainnet
|
||||||
|
chainCfgCpy := *chainConfig
|
||||||
|
chainCfgCpy.ChainID = big.NewInt(1)
|
||||||
|
|
||||||
|
// Use the new chainCfgCpy
|
||||||
|
flexChainConfig = &chainCfgCpy
|
||||||
|
}
|
||||||
|
|
||||||
evm := &EVM{
|
evm := &EVM{
|
||||||
Context: blockCtx,
|
Context: blockCtx,
|
||||||
TxContext: txCtx,
|
TxContext: txCtx,
|
||||||
StateDB: statedb,
|
StateDB: statedb,
|
||||||
Config: config,
|
Config: config,
|
||||||
chainConfig: chainConfig,
|
chainConfig: flexChainConfig,
|
||||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
|
chainRules: flexChainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
|
||||||
}
|
}
|
||||||
evm.interpreter = NewEVMInterpreter(evm)
|
evm.interpreter = NewEVMInterpreter(evm)
|
||||||
return evm
|
return evm
|
||||||
|
@ -215,7 +215,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
|||||||
return errors.New("unexpected post-merge header")
|
return errors.New("unexpected post-merge header")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return h.chain.Engine().VerifyHeader(h.chain, header)
|
return h.chain.Engine().VerifyHeader(h.chain, header, nil)
|
||||||
}
|
}
|
||||||
heighter := func() uint64 {
|
heighter := func() uint64 {
|
||||||
return h.chain.CurrentBlock().Number.Uint64()
|
return h.chain.CurrentBlock().Number.Uint64()
|
||||||
|
@ -591,6 +591,11 @@ func (c *ChainConfig) IsPrimordialPulseBlock(num *big.Int) bool {
|
|||||||
return c.PrimordialPulseBlock != nil && c.PrimordialPulseBlock.Cmp(num) == 0
|
return c.PrimordialPulseBlock != nil && c.PrimordialPulseBlock.Cmp(num) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if there is a PrimordialPulse block in the future.
|
||||||
|
func (c *ChainConfig) PrimordialPulseAhead(num *big.Int) bool {
|
||||||
|
return c.PrimordialPulseBlock != nil && c.PrimordialPulseBlock.Cmp(num) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// CheckCompatible checks whether scheduled fork transitions have been imported
|
// CheckCompatible checks whether scheduled fork transitions have been imported
|
||||||
// with a mismatching chain configuration.
|
// with a mismatching chain configuration.
|
||||||
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError {
|
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError {
|
||||||
|
Loading…
Reference in New Issue
Block a user