block: drop staterootinheader, make it a block version 1

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2024-08-29 23:07:15 +03:00
parent dc6c195637
commit 3f902d7a5a
34 changed files with 137 additions and 208 deletions

View file

@ -10,6 +10,12 @@ ProtocolConfiguration:
- node_single:20333
VerifyTransactions: true
P2PSigExtensions: false
Hardforks:
Aspidochelone: 5
Basilisk: 10
Cockatrice: 15
Domovoi: 20
Echidna: 50
ApplicationConfiguration:
SkipBlockVerification: false

View file

@ -373,7 +373,7 @@ func TestAppCall(t *testing.T) {
}
fc := fakechain.NewFakeChain()
ic := interop.NewContext(trigger.Application, fc, dao.NewSimple(storage.NewMemoryStore(), false),
ic := interop.NewContext(trigger.Application, fc, dao.NewSimple(storage.NewMemoryStore()),
interop.DefaultBaseExecFee, native.DefaultStoragePrice, contractGetter, nil, nil, nil, nil, zaptest.NewLogger(t))
t.Run("valid script", func(t *testing.T) {

View file

@ -753,17 +753,23 @@ func convertKeys(validators []dbft.PublicKey) (pubs []*keys.PublicKey) {
}
func (s *service) newBlockFromContext(ctx *dbft.Context[util.Uint256]) dbft.Block[util.Uint256] {
block := &neoBlock{network: s.ProtocolConfiguration.Magic}
var (
blockVersion = uint32(coreb.VersionInitial)
block = &neoBlock{network: s.ProtocolConfiguration.Magic}
)
hfe, ok := s.ProtocolConfiguration.Hardforks[config.HFEchidna.String()]
if ok && hfe <= ctx.BlockIndex {
blockVersion = coreb.VersionEchidna
}
block.Block.Timestamp = ctx.Timestamp / nsInMs
block.Block.Nonce = ctx.Nonce
block.Block.Index = ctx.BlockIndex
if s.ProtocolConfiguration.StateRootInHeader {
if blockVersion > coreb.VersionInitial {
sr, err := s.Chain.GetStateRoot(ctx.BlockIndex - 1)
if err != nil {
s.log.Fatal(fmt.Sprintf("failed to get state root: %s", err.Error()))
}
block.StateRootEnabled = true
block.PrevStateRoot = sr.Root
}
@ -784,7 +790,7 @@ func (s *service) newBlockFromContext(ctx *dbft.Context[util.Uint256]) dbft.Bloc
}
block.Block.NextConsensus = hash.Hash160(script)
block.Block.PrevHash = ctx.PrevHash
block.Block.Version = coreb.VersionInitial
block.Block.Version = blockVersion
primaryIndex := byte(ctx.PrimaryIndex)
block.Block.PrimaryIndex = primaryIndex

View file

@ -68,11 +68,8 @@ func (b *Block) RebuildMerkleRoot() {
// This is commonly used to create a block from stored data.
// Blocks created from trimmed data will have their Trimmed field
// set to true.
func NewTrimmedFromReader(stateRootEnabled bool, br *io.BinReader) (*Block, error) {
func NewTrimmedFromReader(br *io.BinReader) (*Block, error) {
block := &Block{
Header: Header{
StateRootEnabled: stateRootEnabled,
},
Trimmed: true,
}
@ -93,11 +90,11 @@ func NewTrimmedFromReader(stateRootEnabled bool, br *io.BinReader) (*Block, erro
return block, br.Err
}
// New creates a new blank block with proper state root setting.
func New(stateRootEnabled bool) *Block {
// New creates a new blank block of appropriate version.
func New(version uint32) *Block {
return &Block{
Header: Header{
StateRootEnabled: stateRootEnabled,
Version: version,
},
}
}
@ -213,7 +210,7 @@ func (b *Block) GetExpectedBlockSizeWithoutTransactions(txCount int) int {
size := expectedHeaderSizeWithEmptyWitness - 1 - 1 + // 1 is for the zero-length (new(Header)).Script.Invocation/Verification
io.GetVarSize(&b.Script) +
io.GetVarSize(txCount)
if b.StateRootEnabled {
if b.Version > 0 {
size += util.Uint256Size
}
return size
@ -233,7 +230,7 @@ func (b *Block) ToStackItem() stackitem.Item {
stackitem.NewByteArray(b.NextConsensus.BytesBE()),
stackitem.NewBigInteger(big.NewInt(int64(len(b.Transactions)))),
}
if b.StateRootEnabled {
if b.Version > 0 {
items = append(items, stackitem.NewByteArray(b.PrevStateRoot.BytesBE()))
}

View file

@ -31,7 +31,7 @@ func TestDecodeBlock1(t *testing.T) {
b, err := hex.DecodeString(data["raw"].(string))
require.NoError(t, err)
block := New(false)
block := &Block{}
assert.NoError(t, testserdes.DecodeBinary(b, block))
assert.Equal(t, uint32(data["index"].(float64)), block.Index)
@ -60,7 +60,7 @@ func TestTrimmedBlock(t *testing.T) {
require.NoError(t, buf.Err)
r := io.NewBinReaderFromBuf(buf.Bytes())
trimmedBlock, err := NewTrimmedFromReader(false, r)
trimmedBlock, err := NewTrimmedFromReader(r)
require.NoError(t, err)
assert.True(t, trimmedBlock.Trimmed)
@ -110,7 +110,7 @@ func TestBinBlockDecodeEncode(t *testing.T) {
rawblock := "AAAAAAwIVa2D6Yha3tArd5XnwkAf7deJBsdyyvpYb2xMZGBbkOUNHAsfre0rKA/F+Ox05/bQSXmcRZnzK3M6Z+/TxJUh0MNFeAEAAAAAAAAAAAAAAQAAAADe7nnBifMAmLC6ai65CzqSWKbH/wHGDEDgwCcXkcaFw5MGOp1cpkgApzDTX2/RxKlmPeXTgWYtfEA8g9svUSbZA4TeoGyWvX8LiN0tJKrzajdMGvTVGqVmDEDp6PBmZmRx9CxswtLht6oWa2Uq4rl5diPsLtqXZeZepMlxUSbaCdlFTB7iWQG9yKXWR5hc0sScevvuVwwsUYdlDEDwlhwZrP07E5fEQKttVMYAiL7edd/eW2yoMGZe6Q95g7yXQ69edVHfQb61fBw3DjCpMDZ5lsxp3BgzXglJwMSKkxMMIQIQOn990BZVhZf3lg0nxRakOU/ZaLnmUVXrSwE+QEBAbgwhAqe8Vf6GhOARl2jRBLoweVvcyGYZ6GSt0mFWcj7Rhc1iDCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcIMIQPZDAffY+aQzneRLhCrUazJRLZoYCN7YIxPj4MJ5x7mmRRBe85spQIAWNC7C8DYpwAAAAAAIKpEAAAAAADoAwAAAd7uecGJ8wCYsLpqLrkLOpJYpsf/AQBbCwIA4fUFDBSAzse29bVvUFePc38WLTqxTUZlDQwU3u55wYnzAJiwumouuQs6klimx/8UwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSOQHGDEC4UIzT61GYPx0LdksrF6C2ioYai6fbwpjv3BGAqiyagxiomYGZRLeXZyD67O5FJ86pXRFtSbVYu2YDG+T5ICIgDEDzm/wl+BnHvQXaHQ1rGLtdUMc41wN6I48kPPM7F23gL9sVxGziQIMRLnpTbWHrnzaU9Sy0fXkvIrdJy1KABkSQDEDBwuBuVK+nsZvn1oAscPj6d3FJiUGK9xiHpX9Ipp/5jTnXRBAyzyGc8IZMBVql4WS8kwFe6ojA/9BvFb5eWXnEkxMMIQIQOn990BZVhZf3lg0nxRakOU/ZaLnmUVXrSwE+QEBAbgwhAqe8Vf6GhOARl2jRBLoweVvcyGYZ6GSt0mFWcj7Rhc1iDCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcIMIQPZDAffY+aQzneRLhCrUazJRLZoYCN7YIxPj4MJ5x7mmRRBe85spQDYJLwZwNinAAAAAAAgqkQAAAAAAOgDAAAB3u55wYnzAJiwumouuQs6klimx/8BAF8LAwBA2d2ITQoADBSAzse29bVvUFePc38WLTqxTUZlDQwU3u55wYnzAJiwumouuQs6klimx/8UwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSOQHGDEDWn0D7z2ELqpN8ghcM/PtfFwo56/BfEasfHuSKECJMYxvU47r2ZtSihg59lGxSZzHsvxTy6nsyvJ22ycNhINdJDECl61cg937N/HujKsLMu2wJMS7C54bzJ3q22Czqllvw3Yp809USgKDs+W+3QD7rI+SFs0OhIn0gooCUU6f/13WjDEDr9XdeT5CGTO8CL0JigzcTcucs0GBcqHs8fToO6zPuuCfS7Wh6dyxSCijT4A4S+7BUdW3dsO7828ke1fj8oNxmkxMMIQIQOn990BZVhZf3lg0nxRakOU/ZaLnmUVXrSwE+QEBAbgwhAqe8Vf6GhOARl2jRBLoweVvcyGYZ6GSt0mFWcj7Rhc1iDCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcIMIQPZDAffY+aQzneRLhCrUazJRLZoYCN7YIxPj4MJ5x7mmRRBe85spQ=="
rawblockBytes, _ := base64.StdEncoding.DecodeString(rawblock)
b := New(false)
b := &Block{}
assert.NoError(t, testserdes.DecodeBinary(rawblockBytes, b))
expected := map[string]bool{ // 1 trans
@ -144,12 +144,12 @@ func TestBinBlockDecodeEncode(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, rawblock, base64.StdEncoding.EncodeToString(data))
testserdes.MarshalUnmarshalJSON(t, b, New(false))
testserdes.MarshalUnmarshalJSON(t, b, &Block{})
}
func TestJSONEmptyTx(t *testing.T) {
jblock := `{"hash":"0x5f3fbb43d1e516fe07771e2e873ebc9e2810662401acf603a775aace486220bd","version":0,"previousblockhash":"0x1f4d1defa46faa5e7b9b8d3f79a06bec777d7c26c4aa5f6f5899a291daa87c15","merkleroot":"0x0000000000000000000000000000000000000000000000000000000000000000","time":1627894840919,"nonce":"BA8E021F1AEEA3F6","index":1,"nextconsensus":"NVg7LjGcUSrgxgjX3zEgqaksfMaiS8Z6e1","primary":0,"witnesses":[{"invocation":"DEAq7W/jUhpMon1t9muqXKfBvNyGwLfFFM1vAxrMKvUl6MqK+LL/lJAJP9uAk/cberIWWhSsdcxUtltkBLemg/VuDECQZGuvP93JlZga2ml8cnbe5cNiGgO0EMrbGYyzvgr8calP5SwMNPSYms10gIHxlsuXDU++EQpZu/vKxfHoxdC5DEDgsA3POVZdfN+i5+ekvtsaIvif42n0GC+dZi3Rp37ETmt4NtkoK2I2UXi+WIjm5yXLJsPhAvEV6cJSrvqBdsQBDEDTS6NU+kB+tgeBe9lWv+6y0L2qcUBIaUxiTCaNWZtLPghQICBvjDz1/9ttJRXG3I5N9CFDjjLKCpdIY842HW4/DEC+wlWjkCzVqzKslvpCKZbEPUGIf87CFAD88xqzl26m/TpTUcT0+D5oI2bVzAk0mcdBTPnyjcNbv17BFmr63+09","verification":"FQwhAkhv0VcCxEkKJnAxEqXMHQkj/Wl6M0Br1aHADgATsJpwDCECTHt/tsMQ/M8bozsIJRnYKWTqk4aNZ2Zi1KWa1UjfDn0MIQKq7DhHD2qtAELG6HfP2Ah9Jnaw9Rb93TYoAbm9OTY5ngwhA7IJ/U9TpxcOpERODLCmu2pTwr0BaSaYnPhfmw+6F6cMDCEDuNnVdx2PUTqghpucyNUJhkA7eMbaNokGOMPUalrc4EoMIQLKDidpe5wkj28W4IX9AGHib0TahbWO6DXBEMql7DulVAwhAt9I9g6PPgHEj/QLm38TENeosqGTGIvv4cLj33QOiVCTF0Ge0Nw6"}],"tx":[]}`
b := New(false)
b := &Block{}
require.NoError(t, json.Unmarshal([]byte(jblock), b))
s, err := json.Marshal(b)
require.NoError(t, err)
@ -166,7 +166,7 @@ func TestBlockSizeCalculation(t *testing.T) {
rawBlock := "AAAAAAwIVa2D6Yha3tArd5XnwkAf7deJBsdyyvpYb2xMZGBbkOUNHAsfre0rKA/F+Ox05/bQSXmcRZnzK3M6Z+/TxJUh0MNFeAEAAAAAAAAAAAAAAQAAAADe7nnBifMAmLC6ai65CzqSWKbH/wHGDEDgwCcXkcaFw5MGOp1cpkgApzDTX2/RxKlmPeXTgWYtfEA8g9svUSbZA4TeoGyWvX8LiN0tJKrzajdMGvTVGqVmDEDp6PBmZmRx9CxswtLht6oWa2Uq4rl5diPsLtqXZeZepMlxUSbaCdlFTB7iWQG9yKXWR5hc0sScevvuVwwsUYdlDEDwlhwZrP07E5fEQKttVMYAiL7edd/eW2yoMGZe6Q95g7yXQ69edVHfQb61fBw3DjCpMDZ5lsxp3BgzXglJwMSKkxMMIQIQOn990BZVhZf3lg0nxRakOU/ZaLnmUVXrSwE+QEBAbgwhAqe8Vf6GhOARl2jRBLoweVvcyGYZ6GSt0mFWcj7Rhc1iDCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcIMIQPZDAffY+aQzneRLhCrUazJRLZoYCN7YIxPj4MJ5x7mmRRBe85spQIAWNC7C8DYpwAAAAAAIKpEAAAAAADoAwAAAd7uecGJ8wCYsLpqLrkLOpJYpsf/AQBbCwIA4fUFDBSAzse29bVvUFePc38WLTqxTUZlDQwU3u55wYnzAJiwumouuQs6klimx/8UwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSOQHGDEC4UIzT61GYPx0LdksrF6C2ioYai6fbwpjv3BGAqiyagxiomYGZRLeXZyD67O5FJ86pXRFtSbVYu2YDG+T5ICIgDEDzm/wl+BnHvQXaHQ1rGLtdUMc41wN6I48kPPM7F23gL9sVxGziQIMRLnpTbWHrnzaU9Sy0fXkvIrdJy1KABkSQDEDBwuBuVK+nsZvn1oAscPj6d3FJiUGK9xiHpX9Ipp/5jTnXRBAyzyGc8IZMBVql4WS8kwFe6ojA/9BvFb5eWXnEkxMMIQIQOn990BZVhZf3lg0nxRakOU/ZaLnmUVXrSwE+QEBAbgwhAqe8Vf6GhOARl2jRBLoweVvcyGYZ6GSt0mFWcj7Rhc1iDCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcIMIQPZDAffY+aQzneRLhCrUazJRLZoYCN7YIxPj4MJ5x7mmRRBe85spQDYJLwZwNinAAAAAAAgqkQAAAAAAOgDAAAB3u55wYnzAJiwumouuQs6klimx/8BAF8LAwBA2d2ITQoADBSAzse29bVvUFePc38WLTqxTUZlDQwU3u55wYnzAJiwumouuQs6klimx/8UwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSOQHGDEDWn0D7z2ELqpN8ghcM/PtfFwo56/BfEasfHuSKECJMYxvU47r2ZtSihg59lGxSZzHsvxTy6nsyvJ22ycNhINdJDECl61cg937N/HujKsLMu2wJMS7C54bzJ3q22Czqllvw3Yp809USgKDs+W+3QD7rI+SFs0OhIn0gooCUU6f/13WjDEDr9XdeT5CGTO8CL0JigzcTcucs0GBcqHs8fToO6zPuuCfS7Wh6dyxSCijT4A4S+7BUdW3dsO7828ke1fj8oNxmkxMMIQIQOn990BZVhZf3lg0nxRakOU/ZaLnmUVXrSwE+QEBAbgwhAqe8Vf6GhOARl2jRBLoweVvcyGYZ6GSt0mFWcj7Rhc1iDCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcIMIQPZDAffY+aQzneRLhCrUazJRLZoYCN7YIxPj4MJ5x7mmRRBe85spQ=="
rawBlockBytes, _ := base64.StdEncoding.DecodeString(rawBlock)
b := New(false)
b := &Block{}
assert.NoError(t, testserdes.DecodeBinary(rawBlockBytes, b))
expected := []struct {
@ -243,21 +243,27 @@ func TestGetExpectedBlockSize(t *testing.T) {
check := func(t *testing.T, stateRootEnabled bool) {
t.Run("without transactions", func(t *testing.T) {
b := newDumbBlock()
b.StateRootEnabled = stateRootEnabled
if stateRootEnabled {
b.Version = VersionEchidna
}
b.Transactions = []*transaction.Transaction{}
require.Equal(t, io.GetVarSize(b), b.GetExpectedBlockSize())
require.Equal(t, io.GetVarSize(b), b.GetExpectedBlockSizeWithoutTransactions(0))
})
t.Run("with one transaction", func(t *testing.T) {
b := newDumbBlock()
b.StateRootEnabled = stateRootEnabled
if stateRootEnabled {
b.Version = VersionEchidna
}
expected := io.GetVarSize(b)
require.Equal(t, expected, b.GetExpectedBlockSize())
require.Equal(t, expected-b.Transactions[0].Size(), b.GetExpectedBlockSizeWithoutTransactions(len(b.Transactions)))
})
t.Run("with multiple transactions", func(t *testing.T) {
b := newDumbBlock()
b.StateRootEnabled = stateRootEnabled
if stateRootEnabled {
b.Version = VersionEchidna
}
b.Transactions = make([]*transaction.Transaction, 123)
for i := range b.Transactions {
tx := transaction.New([]byte{byte(opcode.RET)}, int64(i))

View file

@ -13,8 +13,12 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util"
)
// VersionInitial is the default Neo block version.
const VersionInitial uint32 = 0
const (
// VersionInitial is the initial Neo block version.
VersionInitial = iota
// VersionEchidna is StateRoot-enabled Neo block version
VersionEchidna
)
// Header holds the base info of a block.
type Header struct {
@ -45,8 +49,6 @@ type Header struct {
// Script used to validate the block
Script transaction.Witness
// StateRootEnabled specifies if the header contains state root.
StateRootEnabled bool
// PrevStateRoot is the state root of the previous block.
PrevStateRoot util.Uint256
// PrimaryIndex is the index of the primary consensus node for this block.
@ -126,7 +128,7 @@ func (b *Header) encodeHashableFields(bw *io.BinWriter) {
bw.WriteU32LE(b.Index)
bw.WriteB(b.PrimaryIndex)
bw.WriteBytes(b.NextConsensus[:])
if b.StateRootEnabled {
if b.Version > 0 {
bw.WriteBytes(b.PrevStateRoot[:])
}
}
@ -142,7 +144,7 @@ func (b *Header) decodeHashableFields(br *io.BinReader) {
b.Index = br.ReadU32LE()
b.PrimaryIndex = br.ReadB()
br.ReadBytes(b.NextConsensus[:])
if b.StateRootEnabled {
if b.Version > 0 {
br.ReadBytes(b.PrevStateRoot[:])
}
@ -167,7 +169,7 @@ func (b Header) MarshalJSON() ([]byte, error) {
NextConsensus: address.Uint160ToString(b.NextConsensus),
Witnesses: []transaction.Witness{b.Script},
}
if b.StateRootEnabled {
if b.Version > 0 {
aux.PrevStateRoot = &b.PrevStateRoot
}
return json.Marshal(aux)
@ -206,7 +208,7 @@ func (b *Header) UnmarshalJSON(data []byte) error {
b.PrimaryIndex = aux.PrimaryIndex
b.NextConsensus = nextC
b.Script = aux.Witnesses[0]
if b.StateRootEnabled {
if b.Version > 0 {
if aux.PrevStateRoot == nil {
return errors.New("'previousstateroot' is empty")
}

View file

@ -26,12 +26,12 @@ func testHeaderEncodeDecode(t *testing.T, stateRootEnabled bool) {
},
}
if stateRootEnabled {
header.StateRootEnabled = stateRootEnabled
header.Version = VersionEchidna
header.PrevStateRoot = random.Uint256()
}
_ = header.Hash()
headerDecode := &Header{StateRootEnabled: stateRootEnabled}
headerDecode := &Header{}
testserdes.EncodeDecodeBinary(t, &header, headerDecode)
assert.Equal(t, header.Version, headerDecode.Version, "expected both versions to be equal")

View file

@ -18,7 +18,7 @@ func getDecodedBlock(t *testing.T, i int) *Block {
b, err := hex.DecodeString(data["raw"].(string))
require.NoError(t, err)
block := New(false)
block := &Block{}
require.NoError(t, testserdes.DecodeBinary(b, block))
return block

View file

@ -271,9 +271,6 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
zap.Uint32("MaxValidUntilBlockIncrement", cfg.MaxValidUntilBlockIncrement))
}
if cfg.P2PStateExchangeExtensions {
if !cfg.StateRootInHeader {
return nil, errors.New("P2PStatesExchangeExtensions are enabled, but StateRootInHeader is off")
}
if cfg.KeepOnlyLatestState && !cfg.RemoveUntraceableBlocks {
return nil, errors.New("P2PStateExchangeExtensions can be enabled either on MPT-complete node (KeepOnlyLatestState=false) or on light GC-enabled node (RemoveUntraceableBlocks=true)")
}
@ -308,8 +305,8 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
}
bc := &Blockchain{
config: cfg,
dao: dao.NewSimple(s, cfg.StateRootInHeader),
persistent: dao.NewSimple(s, cfg.StateRootInHeader),
dao: dao.NewSimple(s),
persistent: dao.NewSimple(s),
store: s,
stopCh: make(chan struct{}),
runToExitCh: make(chan struct{}),
@ -411,7 +408,6 @@ func (bc *Blockchain) init() error {
bc.log.Info("no storage version found! creating genesis block")
ver = dao.Version{
StoragePrefix: storage.STStorage,
StateRootInHeader: bc.config.StateRootInHeader,
P2PSigExtensions: bc.config.P2PSigExtensions,
P2PStateExchangeExtensions: bc.config.P2PStateExchangeExtensions,
KeepOnlyLatestState: bc.config.Ledger.KeepOnlyLatestState,
@ -434,10 +430,6 @@ func (bc *Blockchain) init() error {
if ver.Value != version {
return fmt.Errorf("storage version mismatch (expected=%s, actual=%s)", version, ver.Value)
}
if ver.StateRootInHeader != bc.config.StateRootInHeader {
return fmt.Errorf("StateRootInHeader setting mismatch (config=%t, db=%t)",
bc.config.StateRootInHeader, ver.StateRootInHeader)
}
if ver.P2PSigExtensions != bc.config.P2PSigExtensions {
return fmt.Errorf("P2PSigExtensions setting mismatch (old=%t, new=%t)",
ver.P2PSigExtensions, bc.config.P2PSigExtensions)
@ -1485,10 +1477,6 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
if expectedHeight != block.Index {
return fmt.Errorf("expected %d, got %d: %w", expectedHeight, block.Index, ErrInvalidBlockIndex)
}
if bc.config.StateRootInHeader != block.StateRootEnabled {
return fmt.Errorf("%w: %v != %v",
ErrHdrStateRootSetting, bc.config.StateRootInHeader, block.StateRootEnabled)
}
if block.Index == bc.HeaderHeight()+1 {
err := bc.addHeaders(!bc.config.SkipBlockVerification, &block.Header)
@ -1749,7 +1737,8 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
// because changes applied are the ones from HALTed transactions.
return fmt.Errorf("error while trying to apply MPT changes: %w", err)
}
if bc.config.StateRootInHeader && bc.HeaderHeight() > sr.Index {
var hfe = config.HFEchidna
if bc.isHardforkEnabled(&hfe, sr.Index) && bc.HeaderHeight() > sr.Index {
h, err := bc.GetHeader(bc.GetHeaderHash(sr.Index + 1))
if err != nil {
err = fmt.Errorf("failed to get next header: %w", err)
@ -2509,14 +2498,12 @@ var (
)
func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error {
if bc.config.StateRootInHeader {
if bc.stateRoot.CurrentLocalHeight() == prevHeader.Index {
if currHeader.Version > block.VersionInitial {
if sr := bc.stateRoot.CurrentLocalStateRoot(); currHeader.PrevStateRoot != sr {
return fmt.Errorf("%w: %s != %s",
ErrHdrInvalidStateRoot, currHeader.PrevStateRoot.StringLE(), sr.StringLE())
}
}
}
if prevHeader.Hash() != currHeader.PrevHash {
return ErrHdrHashMismatch
}
@ -2861,7 +2848,7 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
return nil, fmt.Errorf("failed to retrieve stateroot for height %d: %w", b.Index, err)
}
s := mpt.NewTrieStore(sr.Root, mode, storage.NewPrivateMemCachedStore(bc.dao.Store))
dTrie := dao.NewSimple(s, bc.config.StateRootInHeader)
dTrie := dao.NewSimple(s)
dTrie.Version = bc.dao.Version
// Initialize native cache before passing DAO to interop context constructor, because
// the constructor will call BaseExecFee/StoragePrice policy methods on the passed DAO.
@ -2876,7 +2863,7 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
// getFakeNextBlock returns fake block with the specified index and pre-filled Timestamp field.
func (bc *Blockchain) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, error) {
b := block.New(bc.config.StateRootInHeader)
b := &block.Block{}
b.Index = nextBlockHeight
hdr, err := bc.GetHeader(bc.GetHeaderHash(nextBlockHeight - 1))
if err != nil {

View file

@ -98,7 +98,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
t.Run("mismatch storage version", func(t *testing.T) {
ps = newPS(t)
cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
d := dao.NewSimple(cache, bc.GetConfig().StateRootInHeader)
d := dao.NewSimple(cache)
d.PutVersion(dao.Version{
Value: "0.0.0",
})
@ -108,15 +108,6 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "storage version mismatch"), err)
})
t.Run("mismatch StateRootInHeader", func(t *testing.T) {
ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c)
c.StateRootInHeader = false
}, ps)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "StateRootInHeader setting mismatch"), err)
})
t.Run("mismatch P2PSigExtensions", func(t *testing.T) {
ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
@ -528,16 +519,10 @@ func TestBlockchain_AddBlockStateRoot(t *testing.T) {
sr, err := bc.GetStateModule().GetStateRoot(bc.BlockHeight())
require.NoError(t, err)
b := e.NewUnsignedBlock(t)
b.StateRootEnabled = false
b.PrevStateRoot = util.Uint256{}
e.SignBlock(b)
err = bc.AddBlock(b)
require.ErrorIs(t, err, core.ErrHdrStateRootSetting)
u := sr.Root
u[0] ^= 0xFF
b = e.NewUnsignedBlock(t)
b := e.NewUnsignedBlock(t)
b.Version = block.VersionEchidna
b.PrevStateRoot = u
e.SignBlock(b)
err = bc.AddBlock(b)

View file

@ -64,14 +64,12 @@ func Restore(bc DumperRestorer, r *io.BinReader, skip, count uint32, f func(b *b
}
}
stateRootInHeader := bc.GetConfig().StateRootInHeader
for ; i < skip+count; i++ {
buf, err := readBlock(r)
if err != nil {
return err
}
b := block.New(stateRootInHeader)
b := &block.Block{}
r := io.NewBinReaderFromBuf(buf)
b.DecodeBinary(r)
if r.Err != nil {

View file

@ -68,16 +68,15 @@ type NativeContractCache interface {
}
// NewSimple creates a new simple dao using the provided backend store.
func NewSimple(backend storage.Store, stateRootInHeader bool) *Simple {
func NewSimple(backend storage.Store) *Simple {
st := storage.NewMemCachedStore(backend)
return newSimple(st, stateRootInHeader)
return newSimple(st)
}
func newSimple(st *storage.MemCachedStore, stateRootInHeader bool) *Simple {
func newSimple(st *storage.MemCachedStore) *Simple {
return &Simple{
Version: Version{
StoragePrefix: storage.STStorage,
StateRootInHeader: stateRootInHeader,
},
Store: st,
nativeCache: make(map[int32]NativeContractCache),
@ -92,7 +91,7 @@ func (dao *Simple) GetBatch() *storage.MemBatch {
// GetWrapped returns a new DAO instance with another layer of wrapped
// MemCachedStore around the current DAO Store.
func (dao *Simple) GetWrapped() *Simple {
d := NewSimple(dao.Store, dao.Version.StateRootInHeader)
d := NewSimple(dao.Store)
d.Version = dao.Version
d.nativeCachePS = dao
return d
@ -275,7 +274,7 @@ func (dao *Simple) GetAppExecResults(hash util.Uint256, trig trigger.Type) ([]st
case storage.ExecBlock:
r := io.NewBinReaderFromBuf(bs)
_ = r.ReadB()
_, err = block.NewTrimmedFromReader(dao.Version.StateRootInHeader, r)
_, err = block.NewTrimmedFromReader(r)
if err != nil {
return nil, err
}
@ -432,7 +431,7 @@ func (dao *Simple) getBlock(key []byte) (*block.Block, error) {
// It may be a transaction.
return nil, storage.ErrKeyNotFound
}
block, err := block.NewTrimmedFromReader(dao.Version.StateRootInHeader, r)
block, err := block.NewTrimmedFromReader(r)
if err != nil {
return nil, err
}
@ -442,7 +441,6 @@ func (dao *Simple) getBlock(key []byte) (*block.Block, error) {
// Version represents the current dao version.
type Version struct {
StoragePrefix storage.KeyPrefix
StateRootInHeader bool
P2PSigExtensions bool
P2PStateExchangeExtensions bool
KeepOnlyLatestState bool
@ -451,7 +449,7 @@ type Version struct {
}
const (
stateRootInHeaderBit = 1 << iota
unusedStateRootInHeaderBit = 1 << iota
p2pSigExtensionsBit
p2pStateExchangeExtensionsBit
keepOnlyLatestStateBit
@ -478,7 +476,6 @@ func (v *Version) FromBytes(data []byte) error {
v.Value = string(data[:i])
v.StoragePrefix = storage.KeyPrefix(data[i+1])
v.StateRootInHeader = data[i+2]&stateRootInHeaderBit != 0
v.P2PSigExtensions = data[i+2]&p2pSigExtensionsBit != 0
v.P2PStateExchangeExtensions = data[i+2]&p2pStateExchangeExtensionsBit != 0
v.KeepOnlyLatestState = data[i+2]&keepOnlyLatestStateBit != 0
@ -493,9 +490,6 @@ func (v *Version) FromBytes(data []byte) error {
// Bytes encodes v to a byte-slice.
func (v *Version) Bytes() []byte {
var mask byte
if v.StateRootInHeader {
mask |= stateRootInHeaderBit
}
if v.P2PSigExtensions {
mask |= p2pSigExtensionsBit
}

View file

@ -18,7 +18,7 @@ import (
)
func TestPutGetAndDecode(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
serializable := &TestSerializable{field: random.String(4)}
hash := []byte{1}
require.NoError(t, dao.putWithBuffer(serializable, hash, io.NewBufBinWriter()))
@ -42,7 +42,7 @@ func (t *TestSerializable) DecodeBinary(reader *io.BinReader) {
}
func TestPutGetStorageItem(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
id := int32(random.Int(0, 1024))
key := []byte{0}
storageItem := state.StorageItem{}
@ -52,7 +52,7 @@ func TestPutGetStorageItem(t *testing.T) {
}
func TestDeleteStorageItem(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
id := int32(random.Int(0, 1024))
key := []byte{0}
storageItem := state.StorageItem{}
@ -63,7 +63,7 @@ func TestDeleteStorageItem(t *testing.T) {
}
func TestGetBlock_NotExists(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
hash := random.Uint256()
block, err := dao.GetBlock(hash)
require.Error(t, err)
@ -71,7 +71,7 @@ func TestGetBlock_NotExists(t *testing.T) {
}
func TestPutGetBlock(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
b := &block.Block{
Header: block.Header{
Script: transaction.Witness{
@ -110,18 +110,17 @@ func TestPutGetBlock(t *testing.T) {
}
func TestGetVersion_NoVersion(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
version, err := dao.GetVersion()
require.Error(t, err)
require.Equal(t, "", version.Value)
}
func TestGetVersion(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
expected := Version{
StoragePrefix: 0x42,
P2PSigExtensions: true,
StateRootInHeader: true,
Value: "testVersion",
}
dao.PutVersion(expected)
@ -130,14 +129,14 @@ func TestGetVersion(t *testing.T) {
require.Equal(t, expected, actual)
t.Run("invalid", func(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
dao.Store.Put([]byte{byte(storage.SYSVersion)}, []byte("0.1.2\x00x"))
_, err := dao.GetVersion()
require.Error(t, err)
})
t.Run("old format", func(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
dao.Store.Put([]byte{byte(storage.SYSVersion)}, []byte("0.1.2"))
version, err := dao.GetVersion()
@ -147,14 +146,14 @@ func TestGetVersion(t *testing.T) {
}
func TestGetCurrentHeaderHeight_NoHeader(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
height, err := dao.GetCurrentBlockHeight()
require.Error(t, err)
require.Equal(t, uint32(0), height)
}
func TestGetCurrentHeaderHeight_Store(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
b := &block.Block{
Header: block.Header{
Script: transaction.Witness{
@ -171,7 +170,7 @@ func TestGetCurrentHeaderHeight_Store(t *testing.T) {
func TestStoreAsTransaction(t *testing.T) {
t.Run("no conflicts", func(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 1)
tx.Signers = append(tx.Signers, transaction.Signer{})
tx.Scripts = append(tx.Scripts, transaction.Witness{})
@ -195,7 +194,7 @@ func TestStoreAsTransaction(t *testing.T) {
})
t.Run("with conflicts", func(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
conflictsH := util.Uint256{1, 2, 3}
signer1 := util.Uint160{1, 2, 3}
signer2 := util.Uint160{4, 5, 6}
@ -354,7 +353,7 @@ func TestStoreAsTransaction(t *testing.T) {
}
func BenchmarkStoreAsTransaction(b *testing.B) {
dao := NewSimple(storage.NewMemoryStore(), false)
dao := NewSimple(storage.NewMemoryStore())
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 1)
tx.Attributes = []transaction.Attribute{
{
@ -399,7 +398,7 @@ func BenchmarkStoreAsTransaction(b *testing.B) {
func TestMakeStorageItemKey(t *testing.T) {
var id int32 = 5
dao := NewSimple(storage.NewMemoryStore(), true)
dao := NewSimple(storage.NewMemoryStore())
expected := []byte{byte(storage.STStorage), 0, 0, 0, 0, 1, 2, 3}
binary.LittleEndian.PutUint32(expected[1:5], uint32(id))
@ -418,7 +417,7 @@ func TestMakeStorageItemKey(t *testing.T) {
}
func TestPutGetStateSyncPoint(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), true)
dao := NewSimple(storage.NewMemoryStore())
// empty store
_, err := dao.GetStateSyncPoint()
@ -433,7 +432,7 @@ func TestPutGetStateSyncPoint(t *testing.T) {
}
func TestPutGetStateSyncCurrentBlockHeight(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), true)
dao := NewSimple(storage.NewMemoryStore())
// empty store
_, err := dao.GetStateSyncCurrentBlockHeight()

View file

@ -107,7 +107,7 @@ func newBlockWithState(cfg config.ProtocolConfiguration, index uint32, prev util
b.Index = index
if prevState != nil {
b.StateRootEnabled = true
b.Version = block.VersionEchidna
b.PrevStateRoot = *prevState
}
}, txs...)

View file

@ -72,7 +72,7 @@ func initCheckMultisigVMNoArgs(container *transaction.Transaction) *vm.VM {
ic := interop.NewContext(
trigger.Verification,
fakechain.NewFakeChain(),
dao.NewSimple(storage.NewMemoryStore(), false),
dao.NewSimple(storage.NewMemoryStore()),
interop.DefaultBaseExecFee, native.DefaultStoragePrice, nil, nil, nil, nil,
container,
nil)
@ -178,7 +178,7 @@ func TestCheckSig(t *testing.T) {
require.NoError(t, err)
verifyFunc := ECDSASecp256r1CheckSig
d := dao.NewSimple(storage.NewMemoryStore(), false)
d := dao.NewSimple(storage.NewMemoryStore())
ic := &interop.Context{Network: uint32(netmode.UnitTestNet), DAO: d}
runCase := func(t *testing.T, isErr bool, result any, args ...any) {
ic.SpawnVM()

View file

@ -45,7 +45,7 @@ func TestPlatform(t *testing.T) {
}
func TestGetTime(t *testing.T) {
b := block.New(false)
b := &block.Block{}
b.Timestamp = rand.Uint64()
ic := &interop.Context{VM: vm.New(), Block: b}
require.NoError(t, GetTime(ic))
@ -133,7 +133,7 @@ func TestLog(t *testing.T) {
func TestCurrentSigners(t *testing.T) {
t.Run("container is block", func(t *testing.T) {
b := block.New(false)
b := &block.Block{}
ic := &interop.Context{VM: vm.New(), Container: b}
require.NoError(t, CurrentSigners(ic))
checkStack(t, ic.VM, stackitem.Null{})

View file

@ -18,7 +18,7 @@ import (
func TestDeployGetUpdateDestroyContract(t *testing.T) {
mgmt := newManagement()
mgmt.Policy = newPolicy(false)
d := dao.NewSimple(storage.NewMemoryStore(), false)
d := dao.NewSimple(storage.NewMemoryStore())
ic := &interop.Context{DAO: d}
err := mgmt.Initialize(ic, nil, nil)
require.NoError(t, err)
@ -81,12 +81,12 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) {
func TestManagement_Initialize(t *testing.T) {
t.Run("good", func(t *testing.T) {
d := dao.NewSimple(storage.NewMemoryStore(), false)
d := dao.NewSimple(storage.NewMemoryStore())
mgmt := newManagement()
require.NoError(t, mgmt.InitializeCache(0, d))
})
t.Run("invalid contract state", func(t *testing.T) {
d := dao.NewSimple(storage.NewMemoryStore(), false)
d := dao.NewSimple(storage.NewMemoryStore())
mgmt := newManagement()
d.PutStorageItem(mgmt.ID, []byte{PrefixContract}, state.StorageItem{0xFF})
require.Error(t, mgmt.InitializeCache(0, d))
@ -96,7 +96,7 @@ func TestManagement_Initialize(t *testing.T) {
func TestManagement_GetNEP17Contracts(t *testing.T) {
mgmt := newManagement()
mgmt.Policy = newPolicy(false)
d := dao.NewSimple(storage.NewMemoryStore(), false)
d := dao.NewSimple(storage.NewMemoryStore())
err := mgmt.Initialize(&interop.Context{DAO: d}, nil, nil)
require.NoError(t, err)
require.NoError(t, mgmt.Policy.Initialize(&interop.Context{DAO: d}, nil, nil))

View file

@ -22,7 +22,7 @@ func TestDesignate_DesignateAsRole(t *testing.T) {
des := bc.contracts.Designate
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
bl := block.New(bc.config.StateRootInHeader)
bl := &block.Block{}
bl.Index = bc.BlockHeight() + 1
ic := bc.newInteropContext(trigger.Application, bc.dao, bl, tx)
ic.SpawnVM()

View file

@ -320,9 +320,6 @@ func (s *Module) AddBlock(block *block.Block) error {
if expectedHeight != block.Index {
return fmt.Errorf("expected %d, got %d: invalid block index", expectedHeight, block.Index)
}
if s.bc.GetConfig().StateRootInHeader != block.StateRootEnabled {
return fmt.Errorf("stateroot setting mismatch: %v != %v", s.bc.GetConfig().StateRootInHeader, block.StateRootEnabled)
}
if !s.bc.GetConfig().SkipBlockVerification {
merkle := block.ComputeMerkleRoot()
if !block.MerkleRoot.Equals(merkle) {

View file

@ -54,7 +54,7 @@ func TestModule_PR2019_discussion_r689629704(t *testing.T) {
syncPoint: 1000500,
syncStage: headersSynced,
syncInterval: 100500,
dao: dao.NewSimple(actualStorage, true),
dao: dao.NewSimple(actualStorage),
mptpool: NewPool(),
}
stateSync.billet = mpt.NewBillet(sr, mpt.ModeLatest,

View file

@ -351,20 +351,11 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
require.NoError(t, err)
require.Error(t, module.AddBlock(b))
})
t.Run("error: missing state root in block header", func(t *testing.T) {
b := &block.Block{
Header: block.Header{
Index: uint32(stateSyncPoint) - maxTraceable + 1,
StateRootEnabled: false,
},
}
require.Error(t, module.AddBlock(b))
})
t.Run("error: invalid block merkle root", func(t *testing.T) {
b := &block.Block{
Header: block.Header{
Version: block.VersionEchidna,
Index: uint32(stateSyncPoint) - maxTraceable + 1,
StateRootEnabled: true,
MerkleRoot: util.Uint256{1, 2, 3},
},
}

View file

@ -69,9 +69,17 @@ func CreateGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error)
})
}
var genesisVersion = uint32(block.VersionInitial)
height, ok := cfg.Hardforks[config.HFEchidna.String()]
if ok && height == 0 {
genesisVersion = block.VersionEchidna
}
base := block.Header{
Version: 0,
Version: genesisVersion,
PrevHash: util.Uint256{},
PrevStateRoot: util.Uint256{},
Timestamp: uint64(time.Date(2016, 7, 15, 15, 8, 21, 0, time.UTC).Unix()) * 1000, // Milliseconds.
Nonce: 2083236893,
Index: 0,
@ -80,7 +88,6 @@ func CreateGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error)
InvocationScript: []byte{},
VerificationScript: []byte{byte(opcode.PUSH1)},
},
StateRootEnabled: cfg.StateRootInHeader,
}
b := &block.Block{

View file

@ -7,6 +7,7 @@ import (
"strings"
"testing"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block"
@ -347,6 +348,7 @@ func (e *Executor) NewUnsignedBlock(t testing.TB, txs ...*transaction.Transactio
lastBlock := e.TopBlock(t)
b := &block.Block{
Header: block.Header{
Index: e.Chain.BlockHeight() + 1,
NextConsensus: e.Validator.ScriptHash(),
Script: transaction.Witness{
VerificationScript: e.Validator.Script(),
@ -355,12 +357,12 @@ func (e *Executor) NewUnsignedBlock(t testing.TB, txs ...*transaction.Transactio
},
Transactions: txs,
}
if e.Chain.GetConfig().StateRootInHeader {
b.StateRootEnabled = true
hfe, ok := e.Chain.GetConfig().Hardforks[config.HFEchidna.String()]
if ok && hfe <= b.Index {
b.Version = block.VersionEchidna
b.PrevStateRoot = e.Chain.GetStateModule().CurrentLocalStateRoot()
}
b.PrevHash = lastBlock.Hash()
b.Index = e.Chain.BlockHeight() + 1
b.RebuildMerkleRoot()
return b
}

View file

@ -28,10 +28,6 @@ type Message struct {
// Compressed message payload.
compressedPayload []byte
// StateRootInHeader specifies if the state root is included in the block header.
// This is needed for correct decoding.
StateRootInHeader bool
}
// MessageFlag represents compression level of a message payload.
@ -145,7 +141,7 @@ func (m *Message) decodePayload() error {
case CMDAddr:
p = &payload.AddressList{}
case CMDBlock:
p = block.New(m.StateRootInHeader)
p = &block.Block{}
case CMDExtensible:
p = payload.NewExtensible()
case CMDP2PNotaryRequest:
@ -157,7 +153,7 @@ func (m *Message) decodePayload() error {
case CMDGetBlockByIndex:
p = &payload.GetBlockByIndex{}
case CMDHeaders:
p = &payload.Headers{StateRootInHeader: m.StateRootInHeader}
p = &payload.Headers{}
case CMDTX:
p, err := transaction.NewTransactionFromBytes(buf)
if err != nil {

View file

@ -163,12 +163,6 @@ func TestEncodeDecodeBlock(t *testing.T) {
t.Run("good", func(t *testing.T) {
testEncodeDecode(t, CMDBlock, newDummyBlock(12, 1))
})
t.Run("invalid state root enabled setting", func(t *testing.T) {
expected := NewMessage(CMDBlock, newDummyBlock(31, 1))
data, err := testserdes.Encode(expected)
require.NoError(t, err)
require.Error(t, testserdes.Decode(data, &Message{StateRootInHeader: true}))
})
}
func TestEncodeDecodeGetBlock(t *testing.T) {
@ -334,7 +328,7 @@ func (f failSer) EncodeBinary(r *io.BinWriter) {
func (failSer) DecodeBinary(w *io.BinReader) {}
func newDummyBlock(height uint32, txCount int) *block.Block {
b := block.New(false)
b := &block.Block{}
b.Index = height
b.PrevHash = random.Uint256()
b.Timestamp = rand.Uint64()

View file

@ -11,8 +11,6 @@ import (
// Headers payload.
type Headers struct {
Hdrs []*block.Header
// StateRootInHeader specifies whether the header contains a state root.
StateRootInHeader bool
}
// Users can at most request 2k headers.
@ -46,7 +44,6 @@ func (p *Headers) DecodeBinary(br *io.BinReader) {
for i := 0; i < int(lenHeaders); i++ {
header := &block.Header{}
header.StateRootEnabled = p.StateRootInHeader
header.DecodeBinary(br)
p.Hdrs[i] = header
}

View file

@ -420,7 +420,7 @@ func TestBlock(t *testing.T) {
s.chain.(*fakechain.FakeChain).Blockheight.Store(12344)
require.Equal(t, uint32(12344), s.chain.BlockHeight())
b := block.New(false)
b := &block.Block{}
b.Index = 12345
s.testHandleMessage(t, nil, CMDBlock, b)
require.Eventually(t, func() bool { return s.chain.BlockHeight() == 12345 }, 2*time.Second, time.Millisecond*500)

View file

@ -166,7 +166,7 @@ func (p *TCPPeer) handleConn() {
r := io.NewBinReaderFromIO(p.conn)
loop:
for {
msg := &Message{StateRootInHeader: p.server.config.StateRootInHeader}
msg := &Message{}
err = msg.Decode(r)
if errors.Is(err, payload.ErrTooManyHeaders) {

View file

@ -95,11 +95,7 @@ func (c *Client) getBlock(param any) (*block.Block, error) {
return nil, err
}
r := io.NewBinReaderFromBuf(resp)
sr, err := c.stateRootInHeader()
if err != nil {
return nil, err
}
b = block.New(sr)
b = &block.Block{}
b.DecodeBinary(r)
if r.Err != nil {
return nil, r.Err
@ -128,11 +124,6 @@ func (c *Client) getBlockVerbose(param any) (*result.Block, error) {
resp = &result.Block{}
err error
)
sr, err := c.stateRootInHeader()
if err != nil {
return nil, err
}
resp.Header.StateRootEnabled = sr
if err = c.performRequest("getblock", params, resp); err != nil {
return nil, err
}
@ -163,13 +154,8 @@ func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) {
if err := c.performRequest("getblockheader", params, &resp); err != nil {
return nil, err
}
sr, err := c.stateRootInHeader()
if err != nil {
return nil, err
}
r := io.NewBinReaderFromBuf(resp)
h = new(block.Header)
h.StateRootEnabled = sr
h.DecodeBinary(r)
if r.Err != nil {
return nil, r.Err
@ -874,18 +860,6 @@ func (c *Client) ValidateAddress(address string) error {
return nil
}
// stateRootInHeader returns true if the state root is contained in the block header.
// Requires Init() before use.
func (c *Client) stateRootInHeader() (bool, error) {
c.cacheLock.RLock()
defer c.cacheLock.RUnlock()
if !c.cache.initDone {
return false, errNetworkNotInitialized
}
return c.cache.stateRootInHeader, nil
}
// TraverseIterator returns a set of iterator values (maxItemsCount at max) for
// the specified iterator and session. If result contains no elements, then either
// Iterator has no elements or session was expired and terminated by the server.

View file

@ -67,7 +67,7 @@ func getResultBlock1() *result.Block {
if err != nil {
panic(err)
}
b := block.New(false)
b := &block.Block{}
err = testserdes.DecodeBinary(binB, b)
if err != nil {
panic(err)

View file

@ -551,13 +551,7 @@ readloop:
ntf := Notification{Type: event}
switch event {
case neorpc.BlockEventID:
sr, err := c.stateRootInHeader()
if err != nil {
// Client is not initialized.
connCloseErr = fmt.Errorf("failed to fetch StateRootInHeader: %w", err)
break readloop
}
ntf.Value = block.New(sr)
ntf.Value = &block.Block{}
case neorpc.TransactionEventID:
ntf.Value = &transaction.Transaction{}
case neorpc.NotificationEventID:
@ -567,13 +561,7 @@ readloop:
case neorpc.NotaryRequestEventID:
ntf.Value = new(result.NotaryRequestEvent)
case neorpc.HeaderOfAddedBlockEventID:
sr, err := c.stateRootInHeader()
if err != nil {
// Client is not initialized.
connCloseErr = fmt.Errorf("failed to fetch StateRootInHeader: %w", err)
break readloop
}
ntf.Value = &block.New(sr).Header
ntf.Value = &block.Header{}
case neorpc.MissedEventID:
// No value.
default:

View file

@ -2620,7 +2620,7 @@ func (s *Server) submitBlock(reqParams params.Params) (any, *neorpc.Error) {
if err != nil {
return nil, neorpc.NewInvalidParamsError(fmt.Sprintf("missing parameter or not a base64: %s", err))
}
b := block.New(s.stateRootEnabled)
b := &block.Block{}
r := io.NewBinReaderFromBuf(blockBytes)
b.DecodeBinary(r)
if r.Err != nil {

View file

@ -103,7 +103,7 @@ func getTestBlocks(t *testing.T) []*block.Block {
blocks := make([]*block.Block, 0, int(nBlocks))
for i := 0; i < int(nBlocks); i++ {
_ = br.ReadU32LE()
b := block.New(false)
b := &block.Block{}
b.DecodeBinary(br)
require.Nil(t, br.Err)
blocks = append(blocks, b)

View file

@ -170,12 +170,15 @@ func newBlock(bc *core.Blockchain, lastBlock *block.Block, script []byte, txs ..
},
Transactions: txs,
}
if bc.GetConfig().StateRootInHeader {
hfe, ok := bc.GetConfig().Hardforks[config.HFEchidna.String()]
if ok && hfe <= b.Index {
b.Version = block.VersionEchidna
}
if b.Version > block.VersionInitial {
sr, err := bc.GetStateModule().GetStateRoot(bc.BlockHeight())
if err != nil {
return nil, err
}
b.StateRootEnabled = true
b.PrevStateRoot = sr.Root
}
b.RebuildMerkleRoot()