mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 23:25:22 +00:00
core: allow to add several headers with StateRootInHeader on
Problem: with StateRootInHeader setting on only one header of height N+1 can be added to the chain of height N, because we need local stateroot to verify headers (which is calculated for the last stored block N). Thus, adding chunk of headers starting from the current chain's heigh is impossible and (*Blockchain).AddHeaders doesn't have much sense. Solution: verify header.PrevStateRoot only for header N+1. Rest of the headers should be added without PrevStateRoot verification.
This commit is contained in:
parent
3646270af0
commit
9673a04009
3 changed files with 41 additions and 3 deletions
|
@ -782,6 +782,15 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
||||||
// because changes applied are the ones from HALTed transactions.
|
// because changes applied are the ones from HALTed transactions.
|
||||||
return fmt.Errorf("error while trying to apply MPT changes: %w", err)
|
return fmt.Errorf("error while trying to apply MPT changes: %w", err)
|
||||||
}
|
}
|
||||||
|
if bc.config.StateRootInHeader && bc.HeaderHeight() > sr.Index {
|
||||||
|
h, err := bc.GetHeader(bc.GetHeaderHash(int(sr.Index) + 1))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get next header: %w", err)
|
||||||
|
}
|
||||||
|
if h.PrevStateRoot != sr.Root {
|
||||||
|
return fmt.Errorf("local stateroot and next header's PrevStateRoot mismatch: %s vs %s", sr.Root.StringBE(), h.PrevStateRoot.StringBE())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if bc.config.SaveStorageBatch {
|
if bc.config.SaveStorageBatch {
|
||||||
bc.lastBatch = cache.DAO.GetBatch()
|
bc.lastBatch = cache.DAO.GetBatch()
|
||||||
|
@ -1430,9 +1439,11 @@ var (
|
||||||
|
|
||||||
func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error {
|
func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error {
|
||||||
if bc.config.StateRootInHeader {
|
if bc.config.StateRootInHeader {
|
||||||
if sr := bc.stateRoot.CurrentLocalStateRoot(); currHeader.PrevStateRoot != sr {
|
if bc.stateRoot.CurrentLocalHeight() == prevHeader.Index {
|
||||||
return fmt.Errorf("%w: %s != %s",
|
if sr := bc.stateRoot.CurrentLocalStateRoot(); currHeader.PrevStateRoot != sr {
|
||||||
ErrHdrInvalidStateRoot, currHeader.PrevStateRoot.StringLE(), sr.StringLE())
|
return fmt.Errorf("%w: %s != %s",
|
||||||
|
ErrHdrInvalidStateRoot, currHeader.PrevStateRoot.StringLE(), sr.StringLE())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if prevHeader.Hash() != currHeader.PrevHash {
|
if prevHeader.Hash() != currHeader.PrevHash {
|
||||||
|
|
|
@ -158,6 +158,28 @@ func TestAddBlockStateRoot(t *testing.T) {
|
||||||
require.NoError(t, bc.AddBlock(b))
|
require.NoError(t, bc.AddBlock(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddHeadersStateRoot(t *testing.T) {
|
||||||
|
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
|
||||||
|
c.ProtocolConfiguration.StateRootInHeader = true
|
||||||
|
})
|
||||||
|
|
||||||
|
r := bc.stateRoot.CurrentLocalStateRoot()
|
||||||
|
h1 := bc.newBlock().Header
|
||||||
|
|
||||||
|
// invalid stateroot
|
||||||
|
h1.PrevStateRoot[0] ^= 0xFF
|
||||||
|
require.True(t, errors.Is(bc.AddHeaders(&h1), ErrHdrInvalidStateRoot))
|
||||||
|
|
||||||
|
// valid stateroot
|
||||||
|
h1.PrevStateRoot = r
|
||||||
|
require.NoError(t, bc.AddHeaders(&h1))
|
||||||
|
|
||||||
|
// unable to verify stateroot (stateroot is computed for block #0 only => can
|
||||||
|
// verify stateroot of header #1 only) => just store the header
|
||||||
|
h2 := newBlockWithState(bc.config, 2, h1.Hash(), nil).Header
|
||||||
|
require.NoError(t, bc.AddHeaders(&h2))
|
||||||
|
}
|
||||||
|
|
||||||
func TestAddBadBlock(t *testing.T) {
|
func TestAddBadBlock(t *testing.T) {
|
||||||
bc := newTestChain(t)
|
bc := newTestChain(t)
|
||||||
// It has ValidUntilBlock == 0, which is wrong
|
// It has ValidUntilBlock == 0, which is wrong
|
||||||
|
|
|
@ -70,6 +70,11 @@ func (s *Module) CurrentLocalStateRoot() util.Uint256 {
|
||||||
return s.currentLocal.Load().(util.Uint256)
|
return s.currentLocal.Load().(util.Uint256)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CurrentLocalHeight returns height of the local state root.
|
||||||
|
func (s *Module) CurrentLocalHeight() uint32 {
|
||||||
|
return s.localHeight.Load()
|
||||||
|
}
|
||||||
|
|
||||||
// CurrentValidatedHeight returns current state root validated height.
|
// CurrentValidatedHeight returns current state root validated height.
|
||||||
func (s *Module) CurrentValidatedHeight() uint32 {
|
func (s *Module) CurrentValidatedHeight() uint32 {
|
||||||
return s.validatedHeight.Load()
|
return s.validatedHeight.Load()
|
||||||
|
|
Loading…
Reference in a new issue