neo-go/pkg/core/blockchain_core_test.go

488 lines
16 KiB
Go
Raw Normal View History

package core
import (
"bytes"
2021-08-31 15:39:19 +00:00
"encoding/binary"
2021-02-17 07:45:39 +00:00
"fmt"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/nspcc-dev/neo-go/internal/testchain"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io"
2020-09-24 13:33:40 +00:00
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
Implemented rpc server method GetRawTransaction (#135) * Added utility function GetVarSize * 1) Added Size method: this implied that Fixed8 implements now the serializable interface. 2) Added few arithmetic operation (Add, Sub, div): this will be used to calculated networkfeeand feePerByte. Changed return value of the Value() method to int instead of int64. Modified fixed8_test accordingly. * Implemented Size or MarshalJSON method. - Structs accepting the Size method implement the serializable interface. - Structs accepting the MarshalJSON method implements the customized json marshaller interface. * Added fee calculation * Implemented rcp server method GetRawTransaction * Updated Tests * Fixed: 1) NewFixed8 will accept as input int64 2) race condition affecting configDeafault, blockchainDefault * Simplified Size calculation * 1) Removed global variable blockchainDefault, configDefault 2) Extended Blockchainer interface to include the methods: References, FeePerByte, SystemFee, NetworkFee 3) Deleted fee_test.go, fee.go. Moved corresponding methods to blockchain_test.go and blockchain.go respectively 4) Amended tx_raw_output.go * Simplified GetVarSize Method * Replaced ValueAtAndType with ValueWithType * Cosmetic changes + Added test case getrawtransaction_7 * Clean up Print statement * Filled up keys * Aligned verbose logic with the C#-neo implementation * Implemented @Kim requests Refactor server_test.go * Small fixes * Fixed verbose logic Added more tests Cosmetic changes * Replaced assert.NoError with require.NoError * Fixed tests by adding context.Background() as argument * Fixed tests
2019-02-20 17:39:32 +00:00
"github.com/stretchr/testify/require"
2021-08-31 15:39:19 +00:00
"go.uber.org/zap/zaptest"
)
func TestVerifyHeader(t *testing.T) {
bc := newTestChain(t)
2021-03-01 13:44:47 +00:00
prev := bc.topBlock.Load().(*block.Block).Header
t.Run("Invalid", func(t *testing.T) {
t.Run("Hash", func(t *testing.T) {
h := prev.Hash()
h[0] = ^h[0]
hdr := newBlock(bc.config.ProtocolConfiguration, 1, h).Header
require.ErrorIs(t, bc.verifyHeader(&hdr, &prev), ErrHdrHashMismatch)
})
t.Run("Index", func(t *testing.T) {
hdr := newBlock(bc.config.ProtocolConfiguration, 3, prev.Hash()).Header
require.ErrorIs(t, bc.verifyHeader(&hdr, &prev), ErrHdrIndexMismatch)
})
t.Run("Timestamp", func(t *testing.T) {
hdr := newBlock(bc.config.ProtocolConfiguration, 1, prev.Hash()).Header
hdr.Timestamp = 0
require.ErrorIs(t, bc.verifyHeader(&hdr, &prev), ErrHdrInvalidTimestamp)
})
})
t.Run("Valid", func(t *testing.T) {
hdr := newBlock(bc.config.ProtocolConfiguration, 1, prev.Hash()).Header
2021-03-01 13:44:47 +00:00
require.NoError(t, bc.verifyHeader(&hdr, &prev))
})
}
func TestAddBlock(t *testing.T) {
const size = 3
bc := newTestChain(t)
blocks, err := bc.genBlocks(size)
require.NoError(t, err)
lastBlock := blocks[len(blocks)-1]
assert.Equal(t, lastBlock.Index, bc.HeaderHeight())
assert.Equal(t, lastBlock.Hash(), bc.CurrentHeaderHash())
// This one tests persisting blocks, so it does need to persist()
_, err = bc.persist(false)
core: don't spawn goroutine for persist function It doesn't make any sense, in some situations it leads to a number of goroutines created that will Persist one after another (as we can't Persist concurrently). We can manage it better in a single thread. This doesn't change performance in any way, but somewhat reduces resource consumption. It was tested neo-bench (single node, 10 workers, LevelDB) on two machines and block dump processing (RC4 testnet up to 62800 with VerifyBlocks set to false) on i7-8565U. Reference (b9be892bf9f658652e2d1f074f366914dc62e830): Ryzen 9 5950X: RPS 27747.349 27407.726 27520.210 ≈ 27558 ± 0.63% TPS 26992.010 26993.468 27010.966 ≈ 26999 ± 0.04% CPU % 28.928 28.096 29.105 ≈ 28.7 ± 1.88% Mem MB 760.385 726.320 756.118 ≈ 748 ± 2.48% Core i7-8565U: RPS 7783.229 7628.409 7542.340 ≈ 7651 ± 1.60% TPS 7708.436 7607.397 7489.459 ≈ 7602 ± 1.44% CPU % 74.899 71.020 72.697 ≈ 72.9 ± 2.67% Mem MB 438.047 436.967 416.350 ≈ 430 ± 2.84% DB restore: real 0m20.838s 0m21.895s 0m21.794s ≈ 21.51 ± 2.71% user 0m39.091s 0m40.565s 0m41.493s ≈ 40.38 ± 3.00% sys 0m3.184s 0m2.923s 0m3.062s ≈ 3.06 ± 4.27% Patched: Ryzen 9 5950X: RPS 27636.957 27246.911 27462.036 ≈ 27449 ± 0.71% ↓ 0.40% TPS 27003.672 26993.468 27011.696 ≈ 27003 ± 0.03% ↑ 0.01% CPU % 28.562 28.475 28.012 ≈ 28.3 ± 1.04% ↓ 1.39% Mem MB 627.007 648.110 794.895 ≈ 690 ± 13.25% ↓ 7.75% Core i7-8565U: RPS 7497.210 7527.797 7897.532 ≈ 7641 ± 2.92% ↓ 0.13% TPS 7461.128 7482.678 7841.723 ≈ 7595 ± 2.81% ↓ 0.09% CPU % 71.559 73.423 69.005 ≈ 71.3 ± 3.11% ↓ 2.19% Mem MB 393.090 395.899 482.264 ≈ 424 ± 11.96% ↓ 1.40% DB restore: real 0m20.773s 0m21.583s 0m20.522s ≈ 20.96 ± 2.65% ↓ 2.56% user 0m39.322s 0m42.268s 0m38.626s ≈ 40.07 ± 4.82% ↓ 0.77% sys 0m3.006s 0m3.597s 0m3.042s ≈ 3.22 ± 10.31% ↑ 5.23%
2021-07-30 20:47:48 +00:00
require.NoError(t, err)
key := make([]byte, 1+util.Uint256Size)
key[0] = byte(storage.DataExecutable)
for _, block := range blocks {
copy(key[1:], block.Hash().BytesBE())
2020-04-07 09:41:12 +00:00
_, err := bc.dao.Store.Get(key)
require.NoErrorf(t, err, "block %s not persisted", block.Hash())
}
assert.Equal(t, lastBlock.Index, bc.BlockHeight())
assert.Equal(t, lastBlock.Hash(), bc.CurrentHeaderHash())
}
func TestRemoveOldTransfers(t *testing.T) {
2022-09-02 14:20:39 +00:00
// Creating proper number of transfers/blocks takes unnecessary time, so emulate
// some DB with stale entries.
bc := newTestChain(t)
h, err := bc.GetHeader(bc.GetHeaderHash(0))
require.NoError(t, err)
older := h.Timestamp - 1000
newer := h.Timestamp + 1000
acc1 := util.Uint160{1}
acc2 := util.Uint160{2}
acc3 := util.Uint160{3}
ttl := state.TokenTransferLog{Raw: []byte{1}} // It's incorrect, but who cares.
for i := range uint32(3) {
bc.dao.PutTokenTransferLog(acc1, older, i, false, &ttl)
}
for i := range uint32(3) {
bc.dao.PutTokenTransferLog(acc2, newer, i, false, &ttl)
}
for i := range uint32(2) {
bc.dao.PutTokenTransferLog(acc3, older, i, true, &ttl)
}
for i := range uint32(2) {
bc.dao.PutTokenTransferLog(acc3, newer, i, true, &ttl)
}
_, err = bc.dao.Persist()
require.NoError(t, err)
_ = bc.removeOldTransfers(0)
for i := range uint32(2) {
log, err := bc.dao.GetTokenTransferLog(acc1, older, i, false)
require.NoError(t, err)
require.Equal(t, 0, len(log.Raw))
}
log, err := bc.dao.GetTokenTransferLog(acc1, older, 2, false)
require.NoError(t, err)
require.NotEqual(t, 0, len(log.Raw))
for i := range uint32(3) {
log, err = bc.dao.GetTokenTransferLog(acc2, newer, i, false)
require.NoError(t, err)
require.NotEqual(t, 0, len(log.Raw))
}
log, err = bc.dao.GetTokenTransferLog(acc3, older, 0, true)
require.NoError(t, err)
require.Equal(t, 0, len(log.Raw))
log, err = bc.dao.GetTokenTransferLog(acc3, older, 1, true)
require.NoError(t, err)
require.NotEqual(t, 0, len(log.Raw))
for i := range uint32(2) {
log, err = bc.dao.GetTokenTransferLog(acc3, newer, i, true)
require.NoError(t, err)
require.NotEqual(t, 0, len(log.Raw))
}
}
2021-08-31 15:39:19 +00:00
func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
var (
stateSyncInterval = 4
maxTraceable uint32 = 6
)
spountCfg := func(c *config.Config) {
c.ApplicationConfiguration.RemoveUntraceableBlocks = true
2021-08-31 15:39:19 +00:00
c.ProtocolConfiguration.StateRootInHeader = true
c.ProtocolConfiguration.P2PStateExchangeExtensions = true
c.ProtocolConfiguration.StateSyncInterval = stateSyncInterval
c.ProtocolConfiguration.MaxTraceableBlocks = maxTraceable
c.ApplicationConfiguration.KeepOnlyLatestState = true
2021-08-31 15:39:19 +00:00
}
bcSpout := newTestChainWithCustomCfg(t, spountCfg)
// Generate some content.
for range bcSpout.GetConfig().StandbyCommittee {
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
}
2021-08-31 15:39:19 +00:00
// reach next to the latest state sync point and pretend that we've just restored
stateSyncPoint := (int(bcSpout.BlockHeight())/stateSyncInterval + 1) * stateSyncInterval
for i := bcSpout.BlockHeight() + 1; i <= uint32(stateSyncPoint); i++ {
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
}
require.Equal(t, uint32(stateSyncPoint), bcSpout.BlockHeight())
b := bcSpout.newBlock()
require.NoError(t, bcSpout.AddHeaders(&b.Header))
// put storage items with STTemp prefix
batch := storage.NewMemCachedStore(bcSpout.dao.Store)
tempPrefix := storage.STTempStorage
if bcSpout.dao.Version.StoragePrefix == tempPrefix {
tempPrefix = storage.STStorage
}
bPrefix := make([]byte, 1)
bPrefix[0] = byte(bcSpout.dao.Version.StoragePrefix)
bcSpout.dao.Store.Seek(storage.SeekRange{Prefix: bPrefix}, func(k, v []byte) bool {
key := bytes.Clone(k)
key[0] = byte(tempPrefix)
value := bytes.Clone(v)
batch.Put(key, value)
core: allow early Seek stop This simple approach allows to improve the performance of BoltDB and LevelDB in both terms of speed and allocations for retrieving GasPerVote value from the storage. MemoryPS's speed suffers a bit, but we don't use it for production environment. Part of #2322. Benchmark results: name old time/op new time/op delta NEO_GetGASPerVote/MemPS_10RewardRecords_1RewardDistance-8 25.3µs ± 1% 26.4µs ± 9% +4.41% (p=0.043 n=10+9) NEO_GetGASPerVote/MemPS_10RewardRecords_10RewardDistance-8 27.9µs ± 1% 30.1µs ±15% +7.97% (p=0.000 n=10+9) NEO_GetGASPerVote/MemPS_10RewardRecords_100RewardDistance-8 55.1µs ± 1% 60.2µs ± 7% +9.27% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_10RewardRecords_1000RewardDistance-8 353µs ± 2% 416µs ±13% +17.88% (p=0.000 n=8+8) NEO_GetGASPerVote/MemPS_100RewardRecords_1RewardDistance-8 195µs ± 1% 216µs ± 7% +10.42% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_10RewardDistance-8 200µs ± 4% 214µs ± 9% +6.99% (p=0.002 n=9+8) NEO_GetGASPerVote/MemPS_100RewardRecords_100RewardDistance-8 223µs ± 2% 247µs ± 9% +10.60% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_1000RewardDistance-8 612µs ±23% 855µs ±52% +39.60% (p=0.001 n=9+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_1RewardDistance-8 11.3ms ±53% 10.7ms ±50% ~ (p=0.739 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_10RewardDistance-8 12.0ms ±37% 10.4ms ±65% ~ (p=0.853 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_100RewardDistance-8 11.3ms ±40% 10.4ms ±49% ~ (p=0.631 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_1000RewardDistance-8 3.80ms ±45% 3.69ms ±27% ~ (p=0.931 n=6+5) NEO_GetGASPerVote/BoltPS_10RewardRecords_1RewardDistance-8 23.0µs ± 9% 22.6µs ± 4% ~ (p=0.059 n=8+9) NEO_GetGASPerVote/BoltPS_10RewardRecords_10RewardDistance-8 25.9µs ± 5% 24.8µs ± 4% -4.17% (p=0.006 n=10+8) NEO_GetGASPerVote/BoltPS_10RewardRecords_100RewardDistance-8 42.7µs ±13% 38.9µs ± 1% -8.85% (p=0.000 n=9+8) NEO_GetGASPerVote/BoltPS_10RewardRecords_1000RewardDistance-8 80.8µs ±12% 84.9µs ± 9% ~ (p=0.114 n=8+9) NEO_GetGASPerVote/BoltPS_100RewardRecords_1RewardDistance-8 64.3µs ±16% 22.1µs ±23% -65.64% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_100RewardRecords_10RewardDistance-8 61.0µs ±34% 23.2µs ± 8% -62.04% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_100RewardRecords_100RewardDistance-8 62.2µs ±14% 25.7µs ±13% -58.66% (p=0.000 n=9+10) NEO_GetGASPerVote/BoltPS_100RewardRecords_1000RewardDistance-8 359µs ±60% 325µs ±60% ~ (p=0.739 n=10+10) NEO_GetGASPerVote/BoltPS_1000RewardRecords_1RewardDistance-8 242µs ±21% 13µs ±28% -94.49% (p=0.000 n=10+8) NEO_GetGASPerVote/BoltPS_1000RewardRecords_10RewardDistance-8 229µs ±23% 18µs ±70% -92.02% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_1000RewardRecords_100RewardDistance-8 238µs ±28% 20µs ±109% -91.38% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_1000RewardRecords_1000RewardDistance-8 265µs ±20% 77µs ±62% -71.04% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_1RewardDistance-8 25.5µs ± 3% 24.7µs ± 7% ~ (p=0.143 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_10RewardDistance-8 27.4µs ± 2% 27.9µs ± 6% ~ (p=0.280 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_100RewardDistance-8 50.2µs ± 7% 47.4µs ±10% ~ (p=0.156 n=9+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_1000RewardDistance-8 98.2µs ± 9% 94.6µs ±10% ~ (p=0.218 n=10+10) NEO_GetGASPerVote/LevelPS_100RewardRecords_1RewardDistance-8 82.9µs ±13% 32.1µs ±22% -61.30% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_100RewardRecords_10RewardDistance-8 92.2µs ±11% 33.7µs ±12% -63.42% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_100RewardRecords_100RewardDistance-8 88.3µs ±22% 39.4µs ±14% -55.36% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_100RewardRecords_1000RewardDistance-8 106µs ±18% 78µs ±24% -26.20% (p=0.000 n=9+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_1RewardDistance-8 360µs ±24% 29µs ±53% -91.91% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_1000RewardRecords_10RewardDistance-8 353µs ±16% 50µs ±70% -85.72% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_100RewardDistance-8 381µs ±20% 47µs ±111% -87.64% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_1000RewardDistance-8 434µs ±19% 113µs ±41% -74.04% (p=0.000 n=10+10) name old alloc/op new alloc/op delta NEO_GetGASPerVote/MemPS_10RewardRecords_1RewardDistance-8 4.82kB ± 0% 4.26kB ± 1% -11.62% (p=0.000 n=10+9) NEO_GetGASPerVote/MemPS_10RewardRecords_10RewardDistance-8 4.99kB ± 0% 4.41kB ± 1% -11.56% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_10RewardRecords_100RewardDistance-8 8.45kB ± 0% 7.87kB ± 0% -6.88% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_10RewardRecords_1000RewardDistance-8 55.0kB ± 0% 54.5kB ± 0% -0.81% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_1RewardDistance-8 29.1kB ± 0% 21.7kB ± 2% -25.56% (p=0.000 n=9+9) NEO_GetGASPerVote/MemPS_100RewardRecords_10RewardDistance-8 29.3kB ± 1% 21.8kB ± 2% -25.74% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_100RewardDistance-8 31.3kB ± 1% 23.6kB ± 1% -24.50% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_1000RewardDistance-8 92.5kB ± 5% 84.7kB ± 3% -8.50% (p=0.000 n=10+9) NEO_GetGASPerVote/MemPS_1000RewardRecords_1RewardDistance-8 324kB ±29% 222kB ±44% -31.33% (p=0.007 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_10RewardDistance-8 308kB ±32% 174kB ±14% -43.56% (p=0.000 n=10+8) NEO_GetGASPerVote/MemPS_1000RewardRecords_100RewardDistance-8 298kB ±23% 178kB ±36% -40.26% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_1000RewardDistance-8 362kB ± 6% 248kB ± 6% -31.54% (p=0.004 n=6+5) NEO_GetGASPerVote/BoltPS_10RewardRecords_1RewardDistance-8 5.15kB ± 3% 4.64kB ± 2% -9.92% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_10RewardRecords_10RewardDistance-8 5.36kB ± 1% 4.75kB ± 5% -11.42% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_10RewardRecords_100RewardDistance-8 8.15kB ± 4% 7.53kB ± 1% -7.62% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_10RewardRecords_1000RewardDistance-8 33.2kB ± 5% 33.2kB ± 7% ~ (p=0.829 n=8+10) NEO_GetGASPerVote/BoltPS_100RewardRecords_1RewardDistance-8 20.1kB ± 7% 5.8kB ±13% -70.90% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_100RewardRecords_10RewardDistance-8 19.8kB ±14% 6.2kB ± 5% -68.87% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_100RewardRecords_100RewardDistance-8 21.7kB ± 6% 8.0kB ± 7% -63.20% (p=0.000 n=9+10) NEO_GetGASPerVote/BoltPS_100RewardRecords_1000RewardDistance-8 98.5kB ±44% 81.8kB ±48% ~ (p=0.143 n=10+10) NEO_GetGASPerVote/BoltPS_1000RewardRecords_1RewardDistance-8 130kB ± 4% 4kB ± 9% -96.69% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_1000RewardRecords_10RewardDistance-8 131kB ± 4% 5kB ±21% -96.48% (p=0.000 n=9+9) NEO_GetGASPerVote/BoltPS_1000RewardRecords_100RewardDistance-8 132kB ± 4% 6kB ±10% -95.39% (p=0.000 n=10+8) NEO_GetGASPerVote/BoltPS_1000RewardRecords_1000RewardDistance-8 151kB ± 4% 26kB ±10% -82.46% (p=0.000 n=9+9) NEO_GetGASPerVote/LevelPS_10RewardRecords_1RewardDistance-8 5.92kB ± 3% 5.32kB ± 2% -10.01% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_10RewardDistance-8 6.09kB ± 2% 5.48kB ± 2% -10.00% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_100RewardDistance-8 9.61kB ± 1% 9.00kB ± 0% -6.29% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_1000RewardDistance-8 33.4kB ± 7% 32.2kB ± 5% -3.60% (p=0.037 n=10+10) NEO_GetGASPerVote/LevelPS_100RewardRecords_1RewardDistance-8 22.3kB ±10% 9.0kB ±16% -59.78% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_100RewardRecords_10RewardDistance-8 23.6kB ± 6% 8.5kB ±20% -63.76% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_100RewardRecords_100RewardDistance-8 24.2kB ± 9% 11.5kB ± 4% -52.34% (p=0.000 n=10+8) NEO_GetGASPerVote/LevelPS_100RewardRecords_1000RewardDistance-8 44.2kB ± 6% 30.8kB ± 9% -30.24% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_1RewardDistance-8 144kB ± 4% 10kB ±24% -93.39% (p=0.000 n=9+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_10RewardDistance-8 146kB ± 1% 11kB ±37% -92.14% (p=0.000 n=7+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_100RewardDistance-8 149kB ± 3% 11kB ±12% -92.28% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_1000RewardRecords_1000RewardDistance-8 171kB ± 4% 34kB ±12% -80.00% (p=0.000 n=10+10) name old allocs/op new allocs/op delta NEO_GetGASPerVote/MemPS_10RewardRecords_1RewardDistance-8 95.0 ± 0% 74.0 ± 0% -22.11% (p=0.001 n=8+9) NEO_GetGASPerVote/MemPS_10RewardRecords_10RewardDistance-8 100 ± 0% 78 ± 1% -21.70% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_10RewardRecords_100RewardDistance-8 153 ± 0% 131 ± 2% -14.25% (p=0.000 n=6+10) NEO_GetGASPerVote/MemPS_10RewardRecords_1000RewardDistance-8 799 ± 2% 797 ± 4% ~ (p=0.956 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_1RewardDistance-8 438 ± 6% 167 ± 0% -61.86% (p=0.000 n=10+9) NEO_GetGASPerVote/MemPS_100RewardRecords_10RewardDistance-8 446 ± 5% 172 ± 0% -61.38% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_100RewardDistance-8 506 ± 4% 232 ± 1% -54.21% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_100RewardRecords_1000RewardDistance-8 1.31k ± 5% 0.97k ± 4% -26.20% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_1RewardDistance-8 5.06k ± 1% 1.09k ± 2% -78.53% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_10RewardDistance-8 5.02k ± 3% 1.08k ± 0% -78.45% (p=0.000 n=10+8) NEO_GetGASPerVote/MemPS_1000RewardRecords_100RewardDistance-8 5.09k ± 3% 1.15k ± 2% -77.48% (p=0.000 n=10+10) NEO_GetGASPerVote/MemPS_1000RewardRecords_1000RewardDistance-8 5.83k ± 1% 1.87k ± 3% -68.02% (p=0.004 n=6+5) NEO_GetGASPerVote/BoltPS_10RewardRecords_1RewardDistance-8 103 ± 2% 82 ± 1% -20.83% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_10RewardRecords_10RewardDistance-8 107 ± 0% 86 ± 0% -19.63% (p=0.000 n=8+8) NEO_GetGASPerVote/BoltPS_10RewardRecords_100RewardDistance-8 164 ± 1% 139 ± 0% -15.45% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_10RewardRecords_1000RewardDistance-8 820 ± 1% 789 ± 1% -3.70% (p=0.000 n=9+10) NEO_GetGASPerVote/BoltPS_100RewardRecords_1RewardDistance-8 475 ± 0% 94 ± 3% -80.15% (p=0.000 n=10+9) NEO_GetGASPerVote/BoltPS_100RewardRecords_10RewardDistance-8 481 ± 0% 100 ± 2% -79.26% (p=0.000 n=9+9) NEO_GetGASPerVote/BoltPS_100RewardRecords_100RewardDistance-8 549 ± 0% 161 ± 2% -70.69% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_100RewardRecords_1000RewardDistance-8 1.61k ±19% 1.19k ±25% -26.05% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_1000RewardRecords_1RewardDistance-8 4.12k ± 0% 0.08k ± 2% -98.02% (p=0.000 n=10+10) NEO_GetGASPerVote/BoltPS_1000RewardRecords_10RewardDistance-8 4.14k ± 0% 0.09k ± 3% -97.90% (p=0.000 n=9+9) NEO_GetGASPerVote/BoltPS_1000RewardRecords_100RewardDistance-8 4.19k ± 0% 0.15k ± 3% -96.52% (p=0.000 n=9+9) NEO_GetGASPerVote/BoltPS_1000RewardRecords_1000RewardDistance-8 4.82k ± 1% 0.74k ± 1% -84.58% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_10RewardRecords_1RewardDistance-8 112 ± 4% 90 ± 3% -19.45% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_10RewardDistance-8 116 ± 2% 95 ± 2% -17.90% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_100RewardDistance-8 170 ± 3% 148 ± 3% -12.99% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_10RewardRecords_1000RewardDistance-8 800 ± 2% 772 ± 2% -3.50% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_100RewardRecords_1RewardDistance-8 480 ± 3% 118 ± 3% -75.32% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_100RewardRecords_10RewardDistance-8 479 ± 2% 123 ± 3% -74.33% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_100RewardRecords_100RewardDistance-8 542 ± 1% 183 ± 3% -66.34% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_100RewardRecords_1000RewardDistance-8 1.19k ± 1% 0.79k ± 1% -33.41% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_1RewardDistance-8 4.21k ± 1% 0.13k ±21% -96.83% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_10RewardDistance-8 4.23k ± 1% 0.15k ±17% -96.48% (p=0.000 n=10+10) NEO_GetGASPerVote/LevelPS_1000RewardRecords_100RewardDistance-8 4.27k ± 0% 0.19k ± 6% -95.51% (p=0.000 n=10+9) NEO_GetGASPerVote/LevelPS_1000RewardRecords_1000RewardDistance-8 4.89k ± 1% 0.79k ± 2% -83.80% (p=0.000 n=10+10)
2022-01-17 17:41:51 +00:00
return true
2021-08-31 15:39:19 +00:00
})
_, err := batch.Persist()
require.NoError(t, err)
2021-08-31 15:39:19 +00:00
checkNewBlockchainErr := func(t *testing.T, cfg func(c *config.Config), store storage.Store, errText string) {
2021-08-31 15:39:19 +00:00
unitTestNetCfg, err := config.Load("../../config", testchain.Network())
require.NoError(t, err)
cfg(&unitTestNetCfg)
log := zaptest.NewLogger(t)
_, err = NewBlockchain(store, unitTestNetCfg.Blockchain(), log)
if len(errText) != 0 {
2021-08-31 15:39:19 +00:00
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), errText))
2021-08-31 15:39:19 +00:00
} else {
require.NoError(t, err)
}
}
boltCfg := func(c *config.Config) {
spountCfg(c)
c.ApplicationConfiguration.KeepOnlyLatestState = true
2021-08-31 15:39:19 +00:00
}
// manually store statejump stage to check statejump recover process
2022-10-20 10:59:19 +00:00
bPrefix[0] = byte(storage.SYSStateChangeStage)
2021-08-31 15:39:19 +00:00
t.Run("invalid state jump stage format", func(t *testing.T) {
bcSpout.dao.Store.Put(bPrefix, []byte{0x01, 0x02})
checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, "invalid state jump stage format")
2021-08-31 15:39:19 +00:00
})
t.Run("missing state sync point", func(t *testing.T) {
bcSpout.dao.Store.Put(bPrefix, []byte{byte(stateJumpStarted)})
checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, "failed to get state sync point from the storage")
2021-08-31 15:39:19 +00:00
})
2022-10-20 10:59:19 +00:00
t.Run("invalid RemoveUntraceableBlocks setting", func(t *testing.T) {
bcSpout.dao.Store.Put(bPrefix, []byte{byte(stateJumpStarted)})
point := make([]byte, 4)
binary.LittleEndian.PutUint32(point, uint32(stateSyncPoint))
bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point)
checkNewBlockchainErr(t, func(c *config.Config) {
boltCfg(c)
c.ApplicationConfiguration.RemoveUntraceableBlocks = false
}, bcSpout.dao.Store, "P2PStateExchangeExtensions can be enabled either on MPT-complete node")
2022-10-20 10:59:19 +00:00
})
2021-08-31 15:39:19 +00:00
t.Run("invalid state sync point", func(t *testing.T) {
bcSpout.dao.Store.Put(bPrefix, []byte{byte(stateJumpStarted)})
2021-08-31 15:39:19 +00:00
point := make([]byte, 4)
binary.LittleEndian.PutUint32(point, bcSpout.lastHeaderIndex()+1)
bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point)
checkNewBlockchainErr(t, boltCfg, bcSpout.dao.Store, "invalid state sync point")
2021-08-31 15:39:19 +00:00
})
2022-10-20 10:59:19 +00:00
for _, stage := range []stateChangeStage{stateJumpStarted, newStorageItemsAdded, staleBlocksRemoved, 0x03} {
2021-08-31 15:39:19 +00:00
t.Run(fmt.Sprintf("state jump stage %d", stage), func(t *testing.T) {
bcSpout.dao.Store.Put(bPrefix, []byte{byte(stage)})
2021-08-31 15:39:19 +00:00
point := make([]byte, 4)
binary.LittleEndian.PutUint32(point, uint32(stateSyncPoint))
bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point)
var errText string
if stage == 0x03 {
errText = "unknown state jump stage"
}
checkNewBlockchainErr(t, spountCfg, bcSpout.dao.Store, errText)
2021-08-31 15:39:19 +00:00
})
}
}
func TestChainWithVolatileNumOfValidators(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.ValidatorsCount = 0
c.ProtocolConfiguration.CommitteeHistory = map[uint32]uint32{
0: 1,
4: 4,
24: 6,
}
c.ProtocolConfiguration.ValidatorsHistory = map[uint32]uint32{
0: 1,
4: 4,
}
require.NoError(t, c.ProtocolConfiguration.Validate())
})
require.Equal(t, uint32(0), bc.BlockHeight())
priv0 := testchain.PrivateKeyByID(0)
vals := bc.ComputeNextBlockValidators()
script, err := smartcontract.CreateDefaultMultiSigRedeemScript(vals)
require.NoError(t, err)
curWit := transaction.Witness{
VerificationScript: script,
}
for i := 1; i < 26; i++ {
comm, err := bc.GetCommittee()
require.NoError(t, err)
if i < 5 {
require.Equal(t, 1, len(comm))
} else if i < 25 {
require.Equal(t, 4, len(comm))
} else {
require.Equal(t, 6, len(comm))
}
// Mimic consensus.
if bc.config.ShouldUpdateCommitteeAt(uint32(i)) {
vals = bc.ComputeNextBlockValidators()
} else {
vals, err = bc.GetNextBlockValidators()
}
require.NoError(t, err)
if i < 4 {
require.Equalf(t, 1, len(vals), "at %d", i)
} else {
require.Equalf(t, 4, len(vals), "at %d", i)
}
require.NoError(t, err)
script, err := smartcontract.CreateDefaultMultiSigRedeemScript(vals)
require.NoError(t, err)
nextWit := transaction.Witness{
VerificationScript: script,
}
b := &block.Block{
Header: block.Header{
NextConsensus: nextWit.ScriptHash(),
Script: curWit,
},
}
curWit = nextWit
b.PrevHash = bc.GetHeaderHash(uint32(i) - 1)
b.Timestamp = uint64(time.Now().UTC().Unix())*1000 + uint64(i)
b.Index = uint32(i)
b.RebuildMerkleRoot()
if i < 5 {
signa := priv0.SignHashable(uint32(bc.config.Magic), b)
b.Script.InvocationScript = append([]byte{byte(opcode.PUSHDATA1), byte(len(signa))}, signa...)
} else {
b.Script.InvocationScript = testchain.Sign(b)
}
err = bc.AddBlock(b)
require.NoErrorf(t, err, "at %d", i)
}
}
func setSigner(tx *transaction.Transaction, h util.Uint160) {
tx.Signers = []transaction.Signer{{
Account: h,
Scopes: transaction.Global,
}}
}
// This test checks that value of BaseExecFee returned from corresponding Blockchain's method matches
// the one provided to the constructor of new interop context.
func TestBlockchain_BaseExecFeeBaseStoragePrice_Compat(t *testing.T) {
bc := newTestChain(t)
check := func(t *testing.T) {
ic := bc.newInteropContext(trigger.Application, bc.dao, bc.topBlock.Load().(*block.Block), nil)
require.Equal(t, bc.GetBaseExecFee(), ic.BaseExecFee())
require.Equal(t, bc.GetStoragePrice(), ic.BaseStorageFee())
}
t.Run("zero block", func(t *testing.T) {
check(t)
})
t.Run("non-zero block", func(t *testing.T) {
require.NoError(t, bc.AddBlock(bc.newBlock()))
check(t)
})
}
func TestBlockchain_IsRunning(t *testing.T) {
chain := initTestChain(t, nil, nil)
require.False(t, chain.isRunning.Load().(bool))
oldPersisted := atomic.LoadUint32(&chain.persistedHeight)
go chain.Run()
require.NoError(t, chain.AddBlock(chain.newBlock()))
require.Eventually(t, func() bool {
persisted := atomic.LoadUint32(&chain.persistedHeight)
return persisted > oldPersisted
}, 2*persistInterval, 100*time.Millisecond)
require.True(t, chain.isRunning.Load().(bool))
chain.Close()
require.False(t, chain.isRunning.Load().(bool))
}
func TestNewBlockchain_InitHardforks(t *testing.T) {
t.Run("nil set", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = nil
require.NoError(t, c.ProtocolConfiguration.Validate())
})
require.Equal(t, map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
config.HFCockatrice.String(): 0,
config.HFDomovoi.String(): 0,
config.HFEchidna.String(): 0,
}, bc.GetConfig().Hardforks)
})
t.Run("empty set", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = map[string]uint32{}
require.NoError(t, c.ProtocolConfiguration.Validate())
})
require.Equal(t, map[string]uint32{}, bc.GetConfig().Hardforks)
})
t.Run("missing old", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFBasilisk.String(): 5}
require.NoError(t, c.ProtocolConfiguration.Validate())
})
require.Equal(t, map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 5,
}, bc.GetConfig().Hardforks)
})
t.Run("missing new", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFAspidochelone.String(): 5}
require.NoError(t, c.ProtocolConfiguration.Validate())
})
require.Equal(t, map[string]uint32{
config.HFAspidochelone.String(): 5,
}, bc.GetConfig().Hardforks)
})
t.Run("all present", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFAspidochelone.String(): 5, config.HFBasilisk.String(): 10, config.HFCockatrice.String(): 15, config.HFDomovoi.String(): 20, config.HFEchidna.String(): 25}
require.NoError(t, c.ProtocolConfiguration.Validate())
})
require.Equal(t, map[string]uint32{
config.HFAspidochelone.String(): 5,
config.HFBasilisk.String(): 10,
config.HFCockatrice.String(): 15,
config.HFDomovoi.String(): 20,
config.HFEchidna.String(): 25,
}, bc.GetConfig().Hardforks)
})
}
type nopCloserStorage struct {
storage.Store
}
func (nopCloserStorage) Close() error {
return nil
}
func TestBlockchainRestoreStateRootInHeader(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.StateRootInHeader = true
})
require.NoError(t, bc.AddBlock(bc.newBlock()))
require.NoError(t, bc.AddBlock(bc.newBlock()))
require.NoError(t, bc.AddBlock(bc.newBlock()))
w := io.NewBufBinWriter()
require.NoError(t, chaindump.Dump(bc, w.BinWriter, 0, 4))
require.NoError(t, w.Err)
data := w.Bytes()
fcfg := func(c *config.Config) { c.ProtocolConfiguration.StateRootInHeader = true }
initChain := func(st storage.Store) *Blockchain {
chain := initTestChain(t, st, fcfg)
go chain.Run()
return chain
}
t.Run("empty MemoryStore", func(t *testing.T) {
bc := initChain(storage.NewMemoryStore())
r := io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 0, 4, nil))
bc.Close()
})
t.Run("not empty MemoryStore, one block", func(t *testing.T) {
st := nopCloserStorage{Store: storage.NewMemoryStore()}
bc := initChain(st)
r := io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 0, 1, nil))
expected := bc.stateRoot.CurrentLocalStateRoot()
bc.Close()
bc = initChain(st)
actual := bc.stateRoot.CurrentLocalStateRoot()
require.Equal(t, expected, actual)
r = io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 1, 1, nil))
bc.Close()
})
t.Run("not empty MemoryStore, multiple blocks", func(t *testing.T) {
st := nopCloserStorage{Store: storage.NewMemoryStore()}
{
bc := initChain(st)
r := io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 0, 2, nil))
expected := bc.stateRoot.CurrentLocalStateRoot()
bc.Close()
bc = initChain(st)
actual := bc.stateRoot.CurrentLocalStateRoot()
require.Equal(t, expected, actual)
r = io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 2, 1, nil))
bc.Close()
}
})
}