mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 09: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
|
- node_single:20333
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: false
|
||||||
|
Hardforks:
|
||||||
|
Aspidochelone: 5
|
||||||
|
Basilisk: 10
|
||||||
|
Cockatrice: 15
|
||||||
|
Domovoi: 20
|
||||||
|
Echidna: 50
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
|
|
@ -373,7 +373,7 @@ func TestAppCall(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fc := fakechain.NewFakeChain()
|
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))
|
interop.DefaultBaseExecFee, native.DefaultStoragePrice, contractGetter, nil, nil, nil, nil, zaptest.NewLogger(t))
|
||||||
|
|
||||||
t.Run("valid script", func(t *testing.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] {
|
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.Timestamp = ctx.Timestamp / nsInMs
|
||||||
block.Block.Nonce = ctx.Nonce
|
block.Block.Nonce = ctx.Nonce
|
||||||
block.Block.Index = ctx.BlockIndex
|
block.Block.Index = ctx.BlockIndex
|
||||||
if s.ProtocolConfiguration.StateRootInHeader {
|
if blockVersion > coreb.VersionInitial {
|
||||||
sr, err := s.Chain.GetStateRoot(ctx.BlockIndex - 1)
|
sr, err := s.Chain.GetStateRoot(ctx.BlockIndex - 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Fatal(fmt.Sprintf("failed to get state root: %s", err.Error()))
|
s.log.Fatal(fmt.Sprintf("failed to get state root: %s", err.Error()))
|
||||||
}
|
}
|
||||||
block.StateRootEnabled = true
|
|
||||||
block.PrevStateRoot = sr.Root
|
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.NextConsensus = hash.Hash160(script)
|
||||||
block.Block.PrevHash = ctx.PrevHash
|
block.Block.PrevHash = ctx.PrevHash
|
||||||
block.Block.Version = coreb.VersionInitial
|
block.Block.Version = blockVersion
|
||||||
|
|
||||||
primaryIndex := byte(ctx.PrimaryIndex)
|
primaryIndex := byte(ctx.PrimaryIndex)
|
||||||
block.Block.PrimaryIndex = primaryIndex
|
block.Block.PrimaryIndex = primaryIndex
|
||||||
|
|
|
@ -68,11 +68,8 @@ func (b *Block) RebuildMerkleRoot() {
|
||||||
// This is commonly used to create a block from stored data.
|
// This is commonly used to create a block from stored data.
|
||||||
// Blocks created from trimmed data will have their Trimmed field
|
// Blocks created from trimmed data will have their Trimmed field
|
||||||
// set to true.
|
// set to true.
|
||||||
func NewTrimmedFromReader(stateRootEnabled bool, br *io.BinReader) (*Block, error) {
|
func NewTrimmedFromReader(br *io.BinReader) (*Block, error) {
|
||||||
block := &Block{
|
block := &Block{
|
||||||
Header: Header{
|
|
||||||
StateRootEnabled: stateRootEnabled,
|
|
||||||
},
|
|
||||||
Trimmed: true,
|
Trimmed: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,11 +90,11 @@ func NewTrimmedFromReader(stateRootEnabled bool, br *io.BinReader) (*Block, erro
|
||||||
return block, br.Err
|
return block, br.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new blank block with proper state root setting.
|
// New creates a new blank block of appropriate version.
|
||||||
func New(stateRootEnabled bool) *Block {
|
func New(version uint32) *Block {
|
||||||
return &Block{
|
return &Block{
|
||||||
Header: Header{
|
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
|
size := expectedHeaderSizeWithEmptyWitness - 1 - 1 + // 1 is for the zero-length (new(Header)).Script.Invocation/Verification
|
||||||
io.GetVarSize(&b.Script) +
|
io.GetVarSize(&b.Script) +
|
||||||
io.GetVarSize(txCount)
|
io.GetVarSize(txCount)
|
||||||
if b.StateRootEnabled {
|
if b.Version > 0 {
|
||||||
size += util.Uint256Size
|
size += util.Uint256Size
|
||||||
}
|
}
|
||||||
return size
|
return size
|
||||||
|
@ -233,7 +230,7 @@ func (b *Block) ToStackItem() stackitem.Item {
|
||||||
stackitem.NewByteArray(b.NextConsensus.BytesBE()),
|
stackitem.NewByteArray(b.NextConsensus.BytesBE()),
|
||||||
stackitem.NewBigInteger(big.NewInt(int64(len(b.Transactions)))),
|
stackitem.NewBigInteger(big.NewInt(int64(len(b.Transactions)))),
|
||||||
}
|
}
|
||||||
if b.StateRootEnabled {
|
if b.Version > 0 {
|
||||||
items = append(items, stackitem.NewByteArray(b.PrevStateRoot.BytesBE()))
|
items = append(items, stackitem.NewByteArray(b.PrevStateRoot.BytesBE()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ func TestDecodeBlock1(t *testing.T) {
|
||||||
b, err := hex.DecodeString(data["raw"].(string))
|
b, err := hex.DecodeString(data["raw"].(string))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
block := New(false)
|
block := &Block{}
|
||||||
assert.NoError(t, testserdes.DecodeBinary(b, block))
|
assert.NoError(t, testserdes.DecodeBinary(b, block))
|
||||||
|
|
||||||
assert.Equal(t, uint32(data["index"].(float64)), block.Index)
|
assert.Equal(t, uint32(data["index"].(float64)), block.Index)
|
||||||
|
@ -60,7 +60,7 @@ func TestTrimmedBlock(t *testing.T) {
|
||||||
require.NoError(t, buf.Err)
|
require.NoError(t, buf.Err)
|
||||||
|
|
||||||
r := io.NewBinReaderFromBuf(buf.Bytes())
|
r := io.NewBinReaderFromBuf(buf.Bytes())
|
||||||
trimmedBlock, err := NewTrimmedFromReader(false, r)
|
trimmedBlock, err := NewTrimmedFromReader(r)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.True(t, trimmedBlock.Trimmed)
|
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=="
|
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)
|
rawblockBytes, _ := base64.StdEncoding.DecodeString(rawblock)
|
||||||
|
|
||||||
b := New(false)
|
b := &Block{}
|
||||||
|
|
||||||
assert.NoError(t, testserdes.DecodeBinary(rawblockBytes, b))
|
assert.NoError(t, testserdes.DecodeBinary(rawblockBytes, b))
|
||||||
expected := map[string]bool{ // 1 trans
|
expected := map[string]bool{ // 1 trans
|
||||||
|
@ -144,12 +144,12 @@ func TestBinBlockDecodeEncode(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, rawblock, base64.StdEncoding.EncodeToString(data))
|
assert.Equal(t, rawblock, base64.StdEncoding.EncodeToString(data))
|
||||||
|
|
||||||
testserdes.MarshalUnmarshalJSON(t, b, New(false))
|
testserdes.MarshalUnmarshalJSON(t, b, &Block{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJSONEmptyTx(t *testing.T) {
|
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":[]}`
|
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))
|
require.NoError(t, json.Unmarshal([]byte(jblock), b))
|
||||||
s, err := json.Marshal(b)
|
s, err := json.Marshal(b)
|
||||||
require.NoError(t, err)
|
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=="
|
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)
|
rawBlockBytes, _ := base64.StdEncoding.DecodeString(rawBlock)
|
||||||
|
|
||||||
b := New(false)
|
b := &Block{}
|
||||||
assert.NoError(t, testserdes.DecodeBinary(rawBlockBytes, b))
|
assert.NoError(t, testserdes.DecodeBinary(rawBlockBytes, b))
|
||||||
|
|
||||||
expected := []struct {
|
expected := []struct {
|
||||||
|
@ -243,21 +243,27 @@ func TestGetExpectedBlockSize(t *testing.T) {
|
||||||
check := func(t *testing.T, stateRootEnabled bool) {
|
check := func(t *testing.T, stateRootEnabled bool) {
|
||||||
t.Run("without transactions", func(t *testing.T) {
|
t.Run("without transactions", func(t *testing.T) {
|
||||||
b := newDumbBlock()
|
b := newDumbBlock()
|
||||||
b.StateRootEnabled = stateRootEnabled
|
if stateRootEnabled {
|
||||||
|
b.Version = VersionEchidna
|
||||||
|
}
|
||||||
b.Transactions = []*transaction.Transaction{}
|
b.Transactions = []*transaction.Transaction{}
|
||||||
require.Equal(t, io.GetVarSize(b), b.GetExpectedBlockSize())
|
require.Equal(t, io.GetVarSize(b), b.GetExpectedBlockSize())
|
||||||
require.Equal(t, io.GetVarSize(b), b.GetExpectedBlockSizeWithoutTransactions(0))
|
require.Equal(t, io.GetVarSize(b), b.GetExpectedBlockSizeWithoutTransactions(0))
|
||||||
})
|
})
|
||||||
t.Run("with one transaction", func(t *testing.T) {
|
t.Run("with one transaction", func(t *testing.T) {
|
||||||
b := newDumbBlock()
|
b := newDumbBlock()
|
||||||
b.StateRootEnabled = stateRootEnabled
|
if stateRootEnabled {
|
||||||
|
b.Version = VersionEchidna
|
||||||
|
}
|
||||||
expected := io.GetVarSize(b)
|
expected := io.GetVarSize(b)
|
||||||
require.Equal(t, expected, b.GetExpectedBlockSize())
|
require.Equal(t, expected, b.GetExpectedBlockSize())
|
||||||
require.Equal(t, expected-b.Transactions[0].Size(), b.GetExpectedBlockSizeWithoutTransactions(len(b.Transactions)))
|
require.Equal(t, expected-b.Transactions[0].Size(), b.GetExpectedBlockSizeWithoutTransactions(len(b.Transactions)))
|
||||||
})
|
})
|
||||||
t.Run("with multiple transactions", func(t *testing.T) {
|
t.Run("with multiple transactions", func(t *testing.T) {
|
||||||
b := newDumbBlock()
|
b := newDumbBlock()
|
||||||
b.StateRootEnabled = stateRootEnabled
|
if stateRootEnabled {
|
||||||
|
b.Version = VersionEchidna
|
||||||
|
}
|
||||||
b.Transactions = make([]*transaction.Transaction, 123)
|
b.Transactions = make([]*transaction.Transaction, 123)
|
||||||
for i := range b.Transactions {
|
for i := range b.Transactions {
|
||||||
tx := transaction.New([]byte{byte(opcode.RET)}, int64(i))
|
tx := transaction.New([]byte{byte(opcode.RET)}, int64(i))
|
||||||
|
|
|
@ -13,8 +13,12 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VersionInitial is the default Neo block version.
|
const (
|
||||||
const VersionInitial uint32 = 0
|
// 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.
|
// Header holds the base info of a block.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
|
@ -45,8 +49,6 @@ type Header struct {
|
||||||
// Script used to validate the block
|
// Script used to validate the block
|
||||||
Script transaction.Witness
|
Script transaction.Witness
|
||||||
|
|
||||||
// StateRootEnabled specifies if the header contains state root.
|
|
||||||
StateRootEnabled bool
|
|
||||||
// PrevStateRoot is the state root of the previous block.
|
// PrevStateRoot is the state root of the previous block.
|
||||||
PrevStateRoot util.Uint256
|
PrevStateRoot util.Uint256
|
||||||
// PrimaryIndex is the index of the primary consensus node for this block.
|
// 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.WriteU32LE(b.Index)
|
||||||
bw.WriteB(b.PrimaryIndex)
|
bw.WriteB(b.PrimaryIndex)
|
||||||
bw.WriteBytes(b.NextConsensus[:])
|
bw.WriteBytes(b.NextConsensus[:])
|
||||||
if b.StateRootEnabled {
|
if b.Version > 0 {
|
||||||
bw.WriteBytes(b.PrevStateRoot[:])
|
bw.WriteBytes(b.PrevStateRoot[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +144,7 @@ func (b *Header) decodeHashableFields(br *io.BinReader) {
|
||||||
b.Index = br.ReadU32LE()
|
b.Index = br.ReadU32LE()
|
||||||
b.PrimaryIndex = br.ReadB()
|
b.PrimaryIndex = br.ReadB()
|
||||||
br.ReadBytes(b.NextConsensus[:])
|
br.ReadBytes(b.NextConsensus[:])
|
||||||
if b.StateRootEnabled {
|
if b.Version > 0 {
|
||||||
br.ReadBytes(b.PrevStateRoot[:])
|
br.ReadBytes(b.PrevStateRoot[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +169,7 @@ func (b Header) MarshalJSON() ([]byte, error) {
|
||||||
NextConsensus: address.Uint160ToString(b.NextConsensus),
|
NextConsensus: address.Uint160ToString(b.NextConsensus),
|
||||||
Witnesses: []transaction.Witness{b.Script},
|
Witnesses: []transaction.Witness{b.Script},
|
||||||
}
|
}
|
||||||
if b.StateRootEnabled {
|
if b.Version > 0 {
|
||||||
aux.PrevStateRoot = &b.PrevStateRoot
|
aux.PrevStateRoot = &b.PrevStateRoot
|
||||||
}
|
}
|
||||||
return json.Marshal(aux)
|
return json.Marshal(aux)
|
||||||
|
@ -206,7 +208,7 @@ func (b *Header) UnmarshalJSON(data []byte) error {
|
||||||
b.PrimaryIndex = aux.PrimaryIndex
|
b.PrimaryIndex = aux.PrimaryIndex
|
||||||
b.NextConsensus = nextC
|
b.NextConsensus = nextC
|
||||||
b.Script = aux.Witnesses[0]
|
b.Script = aux.Witnesses[0]
|
||||||
if b.StateRootEnabled {
|
if b.Version > 0 {
|
||||||
if aux.PrevStateRoot == nil {
|
if aux.PrevStateRoot == nil {
|
||||||
return errors.New("'previousstateroot' is empty")
|
return errors.New("'previousstateroot' is empty")
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,12 @@ func testHeaderEncodeDecode(t *testing.T, stateRootEnabled bool) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if stateRootEnabled {
|
if stateRootEnabled {
|
||||||
header.StateRootEnabled = stateRootEnabled
|
header.Version = VersionEchidna
|
||||||
header.PrevStateRoot = random.Uint256()
|
header.PrevStateRoot = random.Uint256()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = header.Hash()
|
_ = header.Hash()
|
||||||
headerDecode := &Header{StateRootEnabled: stateRootEnabled}
|
headerDecode := &Header{}
|
||||||
testserdes.EncodeDecodeBinary(t, &header, headerDecode)
|
testserdes.EncodeDecodeBinary(t, &header, headerDecode)
|
||||||
|
|
||||||
assert.Equal(t, header.Version, headerDecode.Version, "expected both versions to be equal")
|
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))
|
b, err := hex.DecodeString(data["raw"].(string))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
block := New(false)
|
block := &Block{}
|
||||||
require.NoError(t, testserdes.DecodeBinary(b, block))
|
require.NoError(t, testserdes.DecodeBinary(b, block))
|
||||||
|
|
||||||
return block
|
return block
|
||||||
|
|
|
@ -271,9 +271,6 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
||||||
zap.Uint32("MaxValidUntilBlockIncrement", cfg.MaxValidUntilBlockIncrement))
|
zap.Uint32("MaxValidUntilBlockIncrement", cfg.MaxValidUntilBlockIncrement))
|
||||||
}
|
}
|
||||||
if cfg.P2PStateExchangeExtensions {
|
if cfg.P2PStateExchangeExtensions {
|
||||||
if !cfg.StateRootInHeader {
|
|
||||||
return nil, errors.New("P2PStatesExchangeExtensions are enabled, but StateRootInHeader is off")
|
|
||||||
}
|
|
||||||
if cfg.KeepOnlyLatestState && !cfg.RemoveUntraceableBlocks {
|
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)")
|
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{
|
bc := &Blockchain{
|
||||||
config: cfg,
|
config: cfg,
|
||||||
dao: dao.NewSimple(s, cfg.StateRootInHeader),
|
dao: dao.NewSimple(s),
|
||||||
persistent: dao.NewSimple(s, cfg.StateRootInHeader),
|
persistent: dao.NewSimple(s),
|
||||||
store: s,
|
store: s,
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
runToExitCh: 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")
|
bc.log.Info("no storage version found! creating genesis block")
|
||||||
ver = dao.Version{
|
ver = dao.Version{
|
||||||
StoragePrefix: storage.STStorage,
|
StoragePrefix: storage.STStorage,
|
||||||
StateRootInHeader: bc.config.StateRootInHeader,
|
|
||||||
P2PSigExtensions: bc.config.P2PSigExtensions,
|
P2PSigExtensions: bc.config.P2PSigExtensions,
|
||||||
P2PStateExchangeExtensions: bc.config.P2PStateExchangeExtensions,
|
P2PStateExchangeExtensions: bc.config.P2PStateExchangeExtensions,
|
||||||
KeepOnlyLatestState: bc.config.Ledger.KeepOnlyLatestState,
|
KeepOnlyLatestState: bc.config.Ledger.KeepOnlyLatestState,
|
||||||
|
@ -434,10 +430,6 @@ func (bc *Blockchain) init() error {
|
||||||
if ver.Value != version {
|
if ver.Value != version {
|
||||||
return fmt.Errorf("storage version mismatch (expected=%s, actual=%s)", version, ver.Value)
|
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 {
|
if ver.P2PSigExtensions != bc.config.P2PSigExtensions {
|
||||||
return fmt.Errorf("P2PSigExtensions setting mismatch (old=%t, new=%t)",
|
return fmt.Errorf("P2PSigExtensions setting mismatch (old=%t, new=%t)",
|
||||||
ver.P2PSigExtensions, bc.config.P2PSigExtensions)
|
ver.P2PSigExtensions, bc.config.P2PSigExtensions)
|
||||||
|
@ -1485,10 +1477,6 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
|
||||||
if expectedHeight != block.Index {
|
if expectedHeight != block.Index {
|
||||||
return fmt.Errorf("expected %d, got %d: %w", expectedHeight, block.Index, ErrInvalidBlockIndex)
|
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 {
|
if block.Index == bc.HeaderHeight()+1 {
|
||||||
err := bc.addHeaders(!bc.config.SkipBlockVerification, &block.Header)
|
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.
|
// 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 {
|
var hfe = config.HFEchidna
|
||||||
|
if bc.isHardforkEnabled(&hfe, sr.Index) && bc.HeaderHeight() > sr.Index {
|
||||||
h, err := bc.GetHeader(bc.GetHeaderHash(sr.Index + 1))
|
h, err := bc.GetHeader(bc.GetHeaderHash(sr.Index + 1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("failed to get next header: %w", err)
|
err = fmt.Errorf("failed to get next header: %w", err)
|
||||||
|
@ -2509,14 +2498,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error {
|
func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error {
|
||||||
if bc.config.StateRootInHeader {
|
if currHeader.Version > block.VersionInitial {
|
||||||
if bc.stateRoot.CurrentLocalHeight() == prevHeader.Index {
|
|
||||||
if sr := bc.stateRoot.CurrentLocalStateRoot(); currHeader.PrevStateRoot != sr {
|
if sr := bc.stateRoot.CurrentLocalStateRoot(); currHeader.PrevStateRoot != sr {
|
||||||
return fmt.Errorf("%w: %s != %s",
|
return fmt.Errorf("%w: %s != %s",
|
||||||
ErrHdrInvalidStateRoot, currHeader.PrevStateRoot.StringLE(), sr.StringLE())
|
ErrHdrInvalidStateRoot, currHeader.PrevStateRoot.StringLE(), sr.StringLE())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if prevHeader.Hash() != currHeader.PrevHash {
|
if prevHeader.Hash() != currHeader.PrevHash {
|
||||||
return ErrHdrHashMismatch
|
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)
|
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))
|
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
|
dTrie.Version = bc.dao.Version
|
||||||
// Initialize native cache before passing DAO to interop context constructor, because
|
// Initialize native cache before passing DAO to interop context constructor, because
|
||||||
// the constructor will call BaseExecFee/StoragePrice policy methods on the passed DAO.
|
// 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.
|
// getFakeNextBlock returns fake block with the specified index and pre-filled Timestamp field.
|
||||||
func (bc *Blockchain) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, error) {
|
func (bc *Blockchain) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, error) {
|
||||||
b := block.New(bc.config.StateRootInHeader)
|
b := &block.Block{}
|
||||||
b.Index = nextBlockHeight
|
b.Index = nextBlockHeight
|
||||||
hdr, err := bc.GetHeader(bc.GetHeaderHash(nextBlockHeight - 1))
|
hdr, err := bc.GetHeader(bc.GetHeaderHash(nextBlockHeight - 1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -98,7 +98,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
|
||||||
t.Run("mismatch storage version", func(t *testing.T) {
|
t.Run("mismatch storage version", func(t *testing.T) {
|
||||||
ps = newPS(t)
|
ps = newPS(t)
|
||||||
cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
|
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{
|
d.PutVersion(dao.Version{
|
||||||
Value: "0.0.0",
|
Value: "0.0.0",
|
||||||
})
|
})
|
||||||
|
@ -108,15 +108,6 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.True(t, strings.Contains(err.Error(), "storage version mismatch"), 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) {
|
t.Run("mismatch P2PSigExtensions", func(t *testing.T) {
|
||||||
ps = newPS(t)
|
ps = newPS(t)
|
||||||
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
|
_, _, _, 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())
|
sr, err := bc.GetStateModule().GetStateRoot(bc.BlockHeight())
|
||||||
require.NoError(t, err)
|
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 := sr.Root
|
||||||
u[0] ^= 0xFF
|
u[0] ^= 0xFF
|
||||||
b = e.NewUnsignedBlock(t)
|
b := e.NewUnsignedBlock(t)
|
||||||
|
b.Version = block.VersionEchidna
|
||||||
b.PrevStateRoot = u
|
b.PrevStateRoot = u
|
||||||
e.SignBlock(b)
|
e.SignBlock(b)
|
||||||
err = bc.AddBlock(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++ {
|
for ; i < skip+count; i++ {
|
||||||
buf, err := readBlock(r)
|
buf, err := readBlock(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b := block.New(stateRootInHeader)
|
b := &block.Block{}
|
||||||
r := io.NewBinReaderFromBuf(buf)
|
r := io.NewBinReaderFromBuf(buf)
|
||||||
b.DecodeBinary(r)
|
b.DecodeBinary(r)
|
||||||
if r.Err != nil {
|
if r.Err != nil {
|
||||||
|
|
|
@ -68,16 +68,15 @@ type NativeContractCache interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimple creates a new simple dao using the provided backend store.
|
// 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)
|
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{
|
return &Simple{
|
||||||
Version: Version{
|
Version: Version{
|
||||||
StoragePrefix: storage.STStorage,
|
StoragePrefix: storage.STStorage,
|
||||||
StateRootInHeader: stateRootInHeader,
|
|
||||||
},
|
},
|
||||||
Store: st,
|
Store: st,
|
||||||
nativeCache: make(map[int32]NativeContractCache),
|
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
|
// GetWrapped returns a new DAO instance with another layer of wrapped
|
||||||
// MemCachedStore around the current DAO Store.
|
// MemCachedStore around the current DAO Store.
|
||||||
func (dao *Simple) GetWrapped() *Simple {
|
func (dao *Simple) GetWrapped() *Simple {
|
||||||
d := NewSimple(dao.Store, dao.Version.StateRootInHeader)
|
d := NewSimple(dao.Store)
|
||||||
d.Version = dao.Version
|
d.Version = dao.Version
|
||||||
d.nativeCachePS = dao
|
d.nativeCachePS = dao
|
||||||
return d
|
return d
|
||||||
|
@ -275,7 +274,7 @@ func (dao *Simple) GetAppExecResults(hash util.Uint256, trig trigger.Type) ([]st
|
||||||
case storage.ExecBlock:
|
case storage.ExecBlock:
|
||||||
r := io.NewBinReaderFromBuf(bs)
|
r := io.NewBinReaderFromBuf(bs)
|
||||||
_ = r.ReadB()
|
_ = r.ReadB()
|
||||||
_, err = block.NewTrimmedFromReader(dao.Version.StateRootInHeader, r)
|
_, err = block.NewTrimmedFromReader(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -432,7 +431,7 @@ func (dao *Simple) getBlock(key []byte) (*block.Block, error) {
|
||||||
// It may be a transaction.
|
// It may be a transaction.
|
||||||
return nil, storage.ErrKeyNotFound
|
return nil, storage.ErrKeyNotFound
|
||||||
}
|
}
|
||||||
block, err := block.NewTrimmedFromReader(dao.Version.StateRootInHeader, r)
|
block, err := block.NewTrimmedFromReader(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -442,7 +441,6 @@ func (dao *Simple) getBlock(key []byte) (*block.Block, error) {
|
||||||
// Version represents the current dao version.
|
// Version represents the current dao version.
|
||||||
type Version struct {
|
type Version struct {
|
||||||
StoragePrefix storage.KeyPrefix
|
StoragePrefix storage.KeyPrefix
|
||||||
StateRootInHeader bool
|
|
||||||
P2PSigExtensions bool
|
P2PSigExtensions bool
|
||||||
P2PStateExchangeExtensions bool
|
P2PStateExchangeExtensions bool
|
||||||
KeepOnlyLatestState bool
|
KeepOnlyLatestState bool
|
||||||
|
@ -451,7 +449,7 @@ type Version struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
stateRootInHeaderBit = 1 << iota
|
unusedStateRootInHeaderBit = 1 << iota
|
||||||
p2pSigExtensionsBit
|
p2pSigExtensionsBit
|
||||||
p2pStateExchangeExtensionsBit
|
p2pStateExchangeExtensionsBit
|
||||||
keepOnlyLatestStateBit
|
keepOnlyLatestStateBit
|
||||||
|
@ -478,7 +476,6 @@ func (v *Version) FromBytes(data []byte) error {
|
||||||
|
|
||||||
v.Value = string(data[:i])
|
v.Value = string(data[:i])
|
||||||
v.StoragePrefix = storage.KeyPrefix(data[i+1])
|
v.StoragePrefix = storage.KeyPrefix(data[i+1])
|
||||||
v.StateRootInHeader = data[i+2]&stateRootInHeaderBit != 0
|
|
||||||
v.P2PSigExtensions = data[i+2]&p2pSigExtensionsBit != 0
|
v.P2PSigExtensions = data[i+2]&p2pSigExtensionsBit != 0
|
||||||
v.P2PStateExchangeExtensions = data[i+2]&p2pStateExchangeExtensionsBit != 0
|
v.P2PStateExchangeExtensions = data[i+2]&p2pStateExchangeExtensionsBit != 0
|
||||||
v.KeepOnlyLatestState = data[i+2]&keepOnlyLatestStateBit != 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.
|
// Bytes encodes v to a byte-slice.
|
||||||
func (v *Version) Bytes() []byte {
|
func (v *Version) Bytes() []byte {
|
||||||
var mask byte
|
var mask byte
|
||||||
if v.StateRootInHeader {
|
|
||||||
mask |= stateRootInHeaderBit
|
|
||||||
}
|
|
||||||
if v.P2PSigExtensions {
|
if v.P2PSigExtensions {
|
||||||
mask |= p2pSigExtensionsBit
|
mask |= p2pSigExtensionsBit
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPutGetAndDecode(t *testing.T) {
|
func TestPutGetAndDecode(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
serializable := &TestSerializable{field: random.String(4)}
|
serializable := &TestSerializable{field: random.String(4)}
|
||||||
hash := []byte{1}
|
hash := []byte{1}
|
||||||
require.NoError(t, dao.putWithBuffer(serializable, hash, io.NewBufBinWriter()))
|
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) {
|
func TestPutGetStorageItem(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
id := int32(random.Int(0, 1024))
|
id := int32(random.Int(0, 1024))
|
||||||
key := []byte{0}
|
key := []byte{0}
|
||||||
storageItem := state.StorageItem{}
|
storageItem := state.StorageItem{}
|
||||||
|
@ -52,7 +52,7 @@ func TestPutGetStorageItem(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteStorageItem(t *testing.T) {
|
func TestDeleteStorageItem(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
id := int32(random.Int(0, 1024))
|
id := int32(random.Int(0, 1024))
|
||||||
key := []byte{0}
|
key := []byte{0}
|
||||||
storageItem := state.StorageItem{}
|
storageItem := state.StorageItem{}
|
||||||
|
@ -63,7 +63,7 @@ func TestDeleteStorageItem(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetBlock_NotExists(t *testing.T) {
|
func TestGetBlock_NotExists(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
hash := random.Uint256()
|
hash := random.Uint256()
|
||||||
block, err := dao.GetBlock(hash)
|
block, err := dao.GetBlock(hash)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
@ -71,7 +71,7 @@ func TestGetBlock_NotExists(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutGetBlock(t *testing.T) {
|
func TestPutGetBlock(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
b := &block.Block{
|
b := &block.Block{
|
||||||
Header: block.Header{
|
Header: block.Header{
|
||||||
Script: transaction.Witness{
|
Script: transaction.Witness{
|
||||||
|
@ -110,18 +110,17 @@ func TestPutGetBlock(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetVersion_NoVersion(t *testing.T) {
|
func TestGetVersion_NoVersion(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
version, err := dao.GetVersion()
|
version, err := dao.GetVersion()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Equal(t, "", version.Value)
|
require.Equal(t, "", version.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetVersion(t *testing.T) {
|
func TestGetVersion(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
expected := Version{
|
expected := Version{
|
||||||
StoragePrefix: 0x42,
|
StoragePrefix: 0x42,
|
||||||
P2PSigExtensions: true,
|
P2PSigExtensions: true,
|
||||||
StateRootInHeader: true,
|
|
||||||
Value: "testVersion",
|
Value: "testVersion",
|
||||||
}
|
}
|
||||||
dao.PutVersion(expected)
|
dao.PutVersion(expected)
|
||||||
|
@ -130,14 +129,14 @@ func TestGetVersion(t *testing.T) {
|
||||||
require.Equal(t, expected, actual)
|
require.Equal(t, expected, actual)
|
||||||
|
|
||||||
t.Run("invalid", func(t *testing.T) {
|
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"))
|
dao.Store.Put([]byte{byte(storage.SYSVersion)}, []byte("0.1.2\x00x"))
|
||||||
|
|
||||||
_, err := dao.GetVersion()
|
_, err := dao.GetVersion()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
t.Run("old format", func(t *testing.T) {
|
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"))
|
dao.Store.Put([]byte{byte(storage.SYSVersion)}, []byte("0.1.2"))
|
||||||
|
|
||||||
version, err := dao.GetVersion()
|
version, err := dao.GetVersion()
|
||||||
|
@ -147,14 +146,14 @@ func TestGetVersion(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCurrentHeaderHeight_NoHeader(t *testing.T) {
|
func TestGetCurrentHeaderHeight_NoHeader(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
height, err := dao.GetCurrentBlockHeight()
|
height, err := dao.GetCurrentBlockHeight()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Equal(t, uint32(0), height)
|
require.Equal(t, uint32(0), height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCurrentHeaderHeight_Store(t *testing.T) {
|
func TestGetCurrentHeaderHeight_Store(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
b := &block.Block{
|
b := &block.Block{
|
||||||
Header: block.Header{
|
Header: block.Header{
|
||||||
Script: transaction.Witness{
|
Script: transaction.Witness{
|
||||||
|
@ -171,7 +170,7 @@ func TestGetCurrentHeaderHeight_Store(t *testing.T) {
|
||||||
|
|
||||||
func TestStoreAsTransaction(t *testing.T) {
|
func TestStoreAsTransaction(t *testing.T) {
|
||||||
t.Run("no conflicts", func(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 := transaction.New([]byte{byte(opcode.PUSH1)}, 1)
|
||||||
tx.Signers = append(tx.Signers, transaction.Signer{})
|
tx.Signers = append(tx.Signers, transaction.Signer{})
|
||||||
tx.Scripts = append(tx.Scripts, transaction.Witness{})
|
tx.Scripts = append(tx.Scripts, transaction.Witness{})
|
||||||
|
@ -195,7 +194,7 @@ func TestStoreAsTransaction(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with conflicts", func(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}
|
conflictsH := util.Uint256{1, 2, 3}
|
||||||
signer1 := util.Uint160{1, 2, 3}
|
signer1 := util.Uint160{1, 2, 3}
|
||||||
signer2 := util.Uint160{4, 5, 6}
|
signer2 := util.Uint160{4, 5, 6}
|
||||||
|
@ -354,7 +353,7 @@ func TestStoreAsTransaction(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkStoreAsTransaction(b *testing.B) {
|
func BenchmarkStoreAsTransaction(b *testing.B) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), false)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 1)
|
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 1)
|
||||||
tx.Attributes = []transaction.Attribute{
|
tx.Attributes = []transaction.Attribute{
|
||||||
{
|
{
|
||||||
|
@ -399,7 +398,7 @@ func BenchmarkStoreAsTransaction(b *testing.B) {
|
||||||
func TestMakeStorageItemKey(t *testing.T) {
|
func TestMakeStorageItemKey(t *testing.T) {
|
||||||
var id int32 = 5
|
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}
|
expected := []byte{byte(storage.STStorage), 0, 0, 0, 0, 1, 2, 3}
|
||||||
binary.LittleEndian.PutUint32(expected[1:5], uint32(id))
|
binary.LittleEndian.PutUint32(expected[1:5], uint32(id))
|
||||||
|
@ -418,7 +417,7 @@ func TestMakeStorageItemKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutGetStateSyncPoint(t *testing.T) {
|
func TestPutGetStateSyncPoint(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), true)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
|
|
||||||
// empty store
|
// empty store
|
||||||
_, err := dao.GetStateSyncPoint()
|
_, err := dao.GetStateSyncPoint()
|
||||||
|
@ -433,7 +432,7 @@ func TestPutGetStateSyncPoint(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutGetStateSyncCurrentBlockHeight(t *testing.T) {
|
func TestPutGetStateSyncCurrentBlockHeight(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), true)
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
|
|
||||||
// empty store
|
// empty store
|
||||||
_, err := dao.GetStateSyncCurrentBlockHeight()
|
_, err := dao.GetStateSyncCurrentBlockHeight()
|
||||||
|
|
|
@ -107,7 +107,7 @@ func newBlockWithState(cfg config.ProtocolConfiguration, index uint32, prev util
|
||||||
b.Index = index
|
b.Index = index
|
||||||
|
|
||||||
if prevState != nil {
|
if prevState != nil {
|
||||||
b.StateRootEnabled = true
|
b.Version = block.VersionEchidna
|
||||||
b.PrevStateRoot = *prevState
|
b.PrevStateRoot = *prevState
|
||||||
}
|
}
|
||||||
}, txs...)
|
}, txs...)
|
||||||
|
|
|
@ -72,7 +72,7 @@ func initCheckMultisigVMNoArgs(container *transaction.Transaction) *vm.VM {
|
||||||
ic := interop.NewContext(
|
ic := interop.NewContext(
|
||||||
trigger.Verification,
|
trigger.Verification,
|
||||||
fakechain.NewFakeChain(),
|
fakechain.NewFakeChain(),
|
||||||
dao.NewSimple(storage.NewMemoryStore(), false),
|
dao.NewSimple(storage.NewMemoryStore()),
|
||||||
interop.DefaultBaseExecFee, native.DefaultStoragePrice, nil, nil, nil, nil,
|
interop.DefaultBaseExecFee, native.DefaultStoragePrice, nil, nil, nil, nil,
|
||||||
container,
|
container,
|
||||||
nil)
|
nil)
|
||||||
|
@ -178,7 +178,7 @@ func TestCheckSig(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
verifyFunc := ECDSASecp256r1CheckSig
|
verifyFunc := ECDSASecp256r1CheckSig
|
||||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
d := dao.NewSimple(storage.NewMemoryStore())
|
||||||
ic := &interop.Context{Network: uint32(netmode.UnitTestNet), DAO: d}
|
ic := &interop.Context{Network: uint32(netmode.UnitTestNet), DAO: d}
|
||||||
runCase := func(t *testing.T, isErr bool, result any, args ...any) {
|
runCase := func(t *testing.T, isErr bool, result any, args ...any) {
|
||||||
ic.SpawnVM()
|
ic.SpawnVM()
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestPlatform(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTime(t *testing.T) {
|
func TestGetTime(t *testing.T) {
|
||||||
b := block.New(false)
|
b := &block.Block{}
|
||||||
b.Timestamp = rand.Uint64()
|
b.Timestamp = rand.Uint64()
|
||||||
ic := &interop.Context{VM: vm.New(), Block: b}
|
ic := &interop.Context{VM: vm.New(), Block: b}
|
||||||
require.NoError(t, GetTime(ic))
|
require.NoError(t, GetTime(ic))
|
||||||
|
@ -133,7 +133,7 @@ func TestLog(t *testing.T) {
|
||||||
|
|
||||||
func TestCurrentSigners(t *testing.T) {
|
func TestCurrentSigners(t *testing.T) {
|
||||||
t.Run("container is block", func(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}
|
ic := &interop.Context{VM: vm.New(), Container: b}
|
||||||
require.NoError(t, CurrentSigners(ic))
|
require.NoError(t, CurrentSigners(ic))
|
||||||
checkStack(t, ic.VM, stackitem.Null{})
|
checkStack(t, ic.VM, stackitem.Null{})
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
func TestDeployGetUpdateDestroyContract(t *testing.T) {
|
func TestDeployGetUpdateDestroyContract(t *testing.T) {
|
||||||
mgmt := newManagement()
|
mgmt := newManagement()
|
||||||
mgmt.Policy = newPolicy(false)
|
mgmt.Policy = newPolicy(false)
|
||||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
d := dao.NewSimple(storage.NewMemoryStore())
|
||||||
ic := &interop.Context{DAO: d}
|
ic := &interop.Context{DAO: d}
|
||||||
err := mgmt.Initialize(ic, nil, nil)
|
err := mgmt.Initialize(ic, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -81,12 +81,12 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) {
|
||||||
|
|
||||||
func TestManagement_Initialize(t *testing.T) {
|
func TestManagement_Initialize(t *testing.T) {
|
||||||
t.Run("good", func(t *testing.T) {
|
t.Run("good", func(t *testing.T) {
|
||||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
d := dao.NewSimple(storage.NewMemoryStore())
|
||||||
mgmt := newManagement()
|
mgmt := newManagement()
|
||||||
require.NoError(t, mgmt.InitializeCache(0, d))
|
require.NoError(t, mgmt.InitializeCache(0, d))
|
||||||
})
|
})
|
||||||
t.Run("invalid contract state", func(t *testing.T) {
|
t.Run("invalid contract state", func(t *testing.T) {
|
||||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
d := dao.NewSimple(storage.NewMemoryStore())
|
||||||
mgmt := newManagement()
|
mgmt := newManagement()
|
||||||
d.PutStorageItem(mgmt.ID, []byte{PrefixContract}, state.StorageItem{0xFF})
|
d.PutStorageItem(mgmt.ID, []byte{PrefixContract}, state.StorageItem{0xFF})
|
||||||
require.Error(t, mgmt.InitializeCache(0, d))
|
require.Error(t, mgmt.InitializeCache(0, d))
|
||||||
|
@ -96,7 +96,7 @@ func TestManagement_Initialize(t *testing.T) {
|
||||||
func TestManagement_GetNEP17Contracts(t *testing.T) {
|
func TestManagement_GetNEP17Contracts(t *testing.T) {
|
||||||
mgmt := newManagement()
|
mgmt := newManagement()
|
||||||
mgmt.Policy = newPolicy(false)
|
mgmt.Policy = newPolicy(false)
|
||||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
d := dao.NewSimple(storage.NewMemoryStore())
|
||||||
err := mgmt.Initialize(&interop.Context{DAO: d}, nil, nil)
|
err := mgmt.Initialize(&interop.Context{DAO: d}, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, mgmt.Policy.Initialize(&interop.Context{DAO: d}, nil, nil))
|
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
|
des := bc.contracts.Designate
|
||||||
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
|
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
|
||||||
bl := block.New(bc.config.StateRootInHeader)
|
bl := &block.Block{}
|
||||||
bl.Index = bc.BlockHeight() + 1
|
bl.Index = bc.BlockHeight() + 1
|
||||||
ic := bc.newInteropContext(trigger.Application, bc.dao, bl, tx)
|
ic := bc.newInteropContext(trigger.Application, bc.dao, bl, tx)
|
||||||
ic.SpawnVM()
|
ic.SpawnVM()
|
||||||
|
|
|
@ -320,9 +320,6 @@ func (s *Module) AddBlock(block *block.Block) error {
|
||||||
if expectedHeight != block.Index {
|
if expectedHeight != block.Index {
|
||||||
return fmt.Errorf("expected %d, got %d: invalid block index", 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 {
|
if !s.bc.GetConfig().SkipBlockVerification {
|
||||||
merkle := block.ComputeMerkleRoot()
|
merkle := block.ComputeMerkleRoot()
|
||||||
if !block.MerkleRoot.Equals(merkle) {
|
if !block.MerkleRoot.Equals(merkle) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ func TestModule_PR2019_discussion_r689629704(t *testing.T) {
|
||||||
syncPoint: 1000500,
|
syncPoint: 1000500,
|
||||||
syncStage: headersSynced,
|
syncStage: headersSynced,
|
||||||
syncInterval: 100500,
|
syncInterval: 100500,
|
||||||
dao: dao.NewSimple(actualStorage, true),
|
dao: dao.NewSimple(actualStorage),
|
||||||
mptpool: NewPool(),
|
mptpool: NewPool(),
|
||||||
}
|
}
|
||||||
stateSync.billet = mpt.NewBillet(sr, mpt.ModeLatest,
|
stateSync.billet = mpt.NewBillet(sr, mpt.ModeLatest,
|
||||||
|
|
|
@ -351,20 +351,11 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Error(t, module.AddBlock(b))
|
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) {
|
t.Run("error: invalid block merkle root", func(t *testing.T) {
|
||||||
b := &block.Block{
|
b := &block.Block{
|
||||||
Header: block.Header{
|
Header: block.Header{
|
||||||
|
Version: block.VersionEchidna,
|
||||||
Index: uint32(stateSyncPoint) - maxTraceable + 1,
|
Index: uint32(stateSyncPoint) - maxTraceable + 1,
|
||||||
StateRootEnabled: true,
|
|
||||||
MerkleRoot: util.Uint256{1, 2, 3},
|
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{
|
base := block.Header{
|
||||||
Version: 0,
|
Version: genesisVersion,
|
||||||
PrevHash: util.Uint256{},
|
PrevHash: util.Uint256{},
|
||||||
|
PrevStateRoot: util.Uint256{},
|
||||||
Timestamp: uint64(time.Date(2016, 7, 15, 15, 8, 21, 0, time.UTC).Unix()) * 1000, // Milliseconds.
|
Timestamp: uint64(time.Date(2016, 7, 15, 15, 8, 21, 0, time.UTC).Unix()) * 1000, // Milliseconds.
|
||||||
Nonce: 2083236893,
|
Nonce: 2083236893,
|
||||||
Index: 0,
|
Index: 0,
|
||||||
|
@ -80,7 +88,6 @@ func CreateGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error)
|
||||||
InvocationScript: []byte{},
|
InvocationScript: []byte{},
|
||||||
VerificationScript: []byte{byte(opcode.PUSH1)},
|
VerificationScript: []byte{byte(opcode.PUSH1)},
|
||||||
},
|
},
|
||||||
StateRootEnabled: cfg.StateRootInHeader,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b := &block.Block{
|
b := &block.Block{
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"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)
|
lastBlock := e.TopBlock(t)
|
||||||
b := &block.Block{
|
b := &block.Block{
|
||||||
Header: block.Header{
|
Header: block.Header{
|
||||||
|
Index: e.Chain.BlockHeight() + 1,
|
||||||
NextConsensus: e.Validator.ScriptHash(),
|
NextConsensus: e.Validator.ScriptHash(),
|
||||||
Script: transaction.Witness{
|
Script: transaction.Witness{
|
||||||
VerificationScript: e.Validator.Script(),
|
VerificationScript: e.Validator.Script(),
|
||||||
|
@ -355,12 +357,12 @@ func (e *Executor) NewUnsignedBlock(t testing.TB, txs ...*transaction.Transactio
|
||||||
},
|
},
|
||||||
Transactions: txs,
|
Transactions: txs,
|
||||||
}
|
}
|
||||||
if e.Chain.GetConfig().StateRootInHeader {
|
hfe, ok := e.Chain.GetConfig().Hardforks[config.HFEchidna.String()]
|
||||||
b.StateRootEnabled = true
|
if ok && hfe <= b.Index {
|
||||||
|
b.Version = block.VersionEchidna
|
||||||
b.PrevStateRoot = e.Chain.GetStateModule().CurrentLocalStateRoot()
|
b.PrevStateRoot = e.Chain.GetStateModule().CurrentLocalStateRoot()
|
||||||
}
|
}
|
||||||
b.PrevHash = lastBlock.Hash()
|
b.PrevHash = lastBlock.Hash()
|
||||||
b.Index = e.Chain.BlockHeight() + 1
|
|
||||||
b.RebuildMerkleRoot()
|
b.RebuildMerkleRoot()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,6 @@ type Message struct {
|
||||||
|
|
||||||
// Compressed message payload.
|
// Compressed message payload.
|
||||||
compressedPayload []byte
|
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.
|
// MessageFlag represents compression level of a message payload.
|
||||||
|
@ -145,7 +141,7 @@ func (m *Message) decodePayload() error {
|
||||||
case CMDAddr:
|
case CMDAddr:
|
||||||
p = &payload.AddressList{}
|
p = &payload.AddressList{}
|
||||||
case CMDBlock:
|
case CMDBlock:
|
||||||
p = block.New(m.StateRootInHeader)
|
p = &block.Block{}
|
||||||
case CMDExtensible:
|
case CMDExtensible:
|
||||||
p = payload.NewExtensible()
|
p = payload.NewExtensible()
|
||||||
case CMDP2PNotaryRequest:
|
case CMDP2PNotaryRequest:
|
||||||
|
@ -157,7 +153,7 @@ func (m *Message) decodePayload() error {
|
||||||
case CMDGetBlockByIndex:
|
case CMDGetBlockByIndex:
|
||||||
p = &payload.GetBlockByIndex{}
|
p = &payload.GetBlockByIndex{}
|
||||||
case CMDHeaders:
|
case CMDHeaders:
|
||||||
p = &payload.Headers{StateRootInHeader: m.StateRootInHeader}
|
p = &payload.Headers{}
|
||||||
case CMDTX:
|
case CMDTX:
|
||||||
p, err := transaction.NewTransactionFromBytes(buf)
|
p, err := transaction.NewTransactionFromBytes(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -163,12 +163,6 @@ func TestEncodeDecodeBlock(t *testing.T) {
|
||||||
t.Run("good", func(t *testing.T) {
|
t.Run("good", func(t *testing.T) {
|
||||||
testEncodeDecode(t, CMDBlock, newDummyBlock(12, 1))
|
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) {
|
func TestEncodeDecodeGetBlock(t *testing.T) {
|
||||||
|
@ -334,7 +328,7 @@ func (f failSer) EncodeBinary(r *io.BinWriter) {
|
||||||
func (failSer) DecodeBinary(w *io.BinReader) {}
|
func (failSer) DecodeBinary(w *io.BinReader) {}
|
||||||
|
|
||||||
func newDummyBlock(height uint32, txCount int) *block.Block {
|
func newDummyBlock(height uint32, txCount int) *block.Block {
|
||||||
b := block.New(false)
|
b := &block.Block{}
|
||||||
b.Index = height
|
b.Index = height
|
||||||
b.PrevHash = random.Uint256()
|
b.PrevHash = random.Uint256()
|
||||||
b.Timestamp = rand.Uint64()
|
b.Timestamp = rand.Uint64()
|
||||||
|
|
|
@ -11,8 +11,6 @@ import (
|
||||||
// Headers payload.
|
// Headers payload.
|
||||||
type Headers struct {
|
type Headers struct {
|
||||||
Hdrs []*block.Header
|
Hdrs []*block.Header
|
||||||
// StateRootInHeader specifies whether the header contains a state root.
|
|
||||||
StateRootInHeader bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Users can at most request 2k headers.
|
// 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++ {
|
for i := 0; i < int(lenHeaders); i++ {
|
||||||
header := &block.Header{}
|
header := &block.Header{}
|
||||||
header.StateRootEnabled = p.StateRootInHeader
|
|
||||||
header.DecodeBinary(br)
|
header.DecodeBinary(br)
|
||||||
p.Hdrs[i] = header
|
p.Hdrs[i] = header
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,7 +420,7 @@ func TestBlock(t *testing.T) {
|
||||||
s.chain.(*fakechain.FakeChain).Blockheight.Store(12344)
|
s.chain.(*fakechain.FakeChain).Blockheight.Store(12344)
|
||||||
require.Equal(t, uint32(12344), s.chain.BlockHeight())
|
require.Equal(t, uint32(12344), s.chain.BlockHeight())
|
||||||
|
|
||||||
b := block.New(false)
|
b := &block.Block{}
|
||||||
b.Index = 12345
|
b.Index = 12345
|
||||||
s.testHandleMessage(t, nil, CMDBlock, b)
|
s.testHandleMessage(t, nil, CMDBlock, b)
|
||||||
require.Eventually(t, func() bool { return s.chain.BlockHeight() == 12345 }, 2*time.Second, time.Millisecond*500)
|
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)
|
r := io.NewBinReaderFromIO(p.conn)
|
||||||
loop:
|
loop:
|
||||||
for {
|
for {
|
||||||
msg := &Message{StateRootInHeader: p.server.config.StateRootInHeader}
|
msg := &Message{}
|
||||||
err = msg.Decode(r)
|
err = msg.Decode(r)
|
||||||
|
|
||||||
if errors.Is(err, payload.ErrTooManyHeaders) {
|
if errors.Is(err, payload.ErrTooManyHeaders) {
|
||||||
|
|
|
@ -95,11 +95,7 @@ func (c *Client) getBlock(param any) (*block.Block, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r := io.NewBinReaderFromBuf(resp)
|
r := io.NewBinReaderFromBuf(resp)
|
||||||
sr, err := c.stateRootInHeader()
|
b = &block.Block{}
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
b = block.New(sr)
|
|
||||||
b.DecodeBinary(r)
|
b.DecodeBinary(r)
|
||||||
if r.Err != nil {
|
if r.Err != nil {
|
||||||
return nil, r.Err
|
return nil, r.Err
|
||||||
|
@ -128,11 +124,6 @@ func (c *Client) getBlockVerbose(param any) (*result.Block, error) {
|
||||||
resp = &result.Block{}
|
resp = &result.Block{}
|
||||||
err error
|
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 {
|
if err = c.performRequest("getblock", params, resp); err != nil {
|
||||||
return nil, err
|
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 {
|
if err := c.performRequest("getblockheader", params, &resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sr, err := c.stateRootInHeader()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r := io.NewBinReaderFromBuf(resp)
|
r := io.NewBinReaderFromBuf(resp)
|
||||||
h = new(block.Header)
|
h = new(block.Header)
|
||||||
h.StateRootEnabled = sr
|
|
||||||
h.DecodeBinary(r)
|
h.DecodeBinary(r)
|
||||||
if r.Err != nil {
|
if r.Err != nil {
|
||||||
return nil, r.Err
|
return nil, r.Err
|
||||||
|
@ -874,18 +860,6 @@ func (c *Client) ValidateAddress(address string) error {
|
||||||
return nil
|
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
|
// TraverseIterator returns a set of iterator values (maxItemsCount at max) for
|
||||||
// the specified iterator and session. If result contains no elements, then either
|
// 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.
|
// Iterator has no elements or session was expired and terminated by the server.
|
||||||
|
|
|
@ -67,7 +67,7 @@ func getResultBlock1() *result.Block {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
b := block.New(false)
|
b := &block.Block{}
|
||||||
err = testserdes.DecodeBinary(binB, b)
|
err = testserdes.DecodeBinary(binB, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -551,13 +551,7 @@ readloop:
|
||||||
ntf := Notification{Type: event}
|
ntf := Notification{Type: event}
|
||||||
switch event {
|
switch event {
|
||||||
case neorpc.BlockEventID:
|
case neorpc.BlockEventID:
|
||||||
sr, err := c.stateRootInHeader()
|
ntf.Value = &block.Block{}
|
||||||
if err != nil {
|
|
||||||
// Client is not initialized.
|
|
||||||
connCloseErr = fmt.Errorf("failed to fetch StateRootInHeader: %w", err)
|
|
||||||
break readloop
|
|
||||||
}
|
|
||||||
ntf.Value = block.New(sr)
|
|
||||||
case neorpc.TransactionEventID:
|
case neorpc.TransactionEventID:
|
||||||
ntf.Value = &transaction.Transaction{}
|
ntf.Value = &transaction.Transaction{}
|
||||||
case neorpc.NotificationEventID:
|
case neorpc.NotificationEventID:
|
||||||
|
@ -567,13 +561,7 @@ readloop:
|
||||||
case neorpc.NotaryRequestEventID:
|
case neorpc.NotaryRequestEventID:
|
||||||
ntf.Value = new(result.NotaryRequestEvent)
|
ntf.Value = new(result.NotaryRequestEvent)
|
||||||
case neorpc.HeaderOfAddedBlockEventID:
|
case neorpc.HeaderOfAddedBlockEventID:
|
||||||
sr, err := c.stateRootInHeader()
|
ntf.Value = &block.Header{}
|
||||||
if err != nil {
|
|
||||||
// Client is not initialized.
|
|
||||||
connCloseErr = fmt.Errorf("failed to fetch StateRootInHeader: %w", err)
|
|
||||||
break readloop
|
|
||||||
}
|
|
||||||
ntf.Value = &block.New(sr).Header
|
|
||||||
case neorpc.MissedEventID:
|
case neorpc.MissedEventID:
|
||||||
// No value.
|
// No value.
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -2620,7 +2620,7 @@ func (s *Server) submitBlock(reqParams params.Params) (any, *neorpc.Error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, neorpc.NewInvalidParamsError(fmt.Sprintf("missing parameter or not a base64: %s", err))
|
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)
|
r := io.NewBinReaderFromBuf(blockBytes)
|
||||||
b.DecodeBinary(r)
|
b.DecodeBinary(r)
|
||||||
if r.Err != nil {
|
if r.Err != nil {
|
||||||
|
|
|
@ -103,7 +103,7 @@ func getTestBlocks(t *testing.T) []*block.Block {
|
||||||
blocks := make([]*block.Block, 0, int(nBlocks))
|
blocks := make([]*block.Block, 0, int(nBlocks))
|
||||||
for i := 0; i < int(nBlocks); i++ {
|
for i := 0; i < int(nBlocks); i++ {
|
||||||
_ = br.ReadU32LE()
|
_ = br.ReadU32LE()
|
||||||
b := block.New(false)
|
b := &block.Block{}
|
||||||
b.DecodeBinary(br)
|
b.DecodeBinary(br)
|
||||||
require.Nil(t, br.Err)
|
require.Nil(t, br.Err)
|
||||||
blocks = append(blocks, b)
|
blocks = append(blocks, b)
|
||||||
|
|
|
@ -170,12 +170,15 @@ func newBlock(bc *core.Blockchain, lastBlock *block.Block, script []byte, txs ..
|
||||||
},
|
},
|
||||||
Transactions: 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())
|
sr, err := bc.GetStateModule().GetStateRoot(bc.BlockHeight())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b.StateRootEnabled = true
|
|
||||||
b.PrevStateRoot = sr.Root
|
b.PrevStateRoot = sr.Root
|
||||||
}
|
}
|
||||||
b.RebuildMerkleRoot()
|
b.RebuildMerkleRoot()
|
||||||
|
|
Loading…
Reference in a new issue