mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-21 23:29:38 +00:00
block: drop staterootinheader, make it a block version 1
Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
parent
dc6c195637
commit
3f902d7a5a
34 changed files with 137 additions and 208 deletions
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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...)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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{})
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue