From 0aedfd0038c1600815e62f40959698dd9596e207 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 1 Sep 2021 14:05:57 +0300 Subject: [PATCH] core: fix bug in MPT pool during Update We need to copy the result of `TryGet` method, otherwice the slice can be modified inside `Add` or `Update` methods, which leads to inconsistent MPT pool state. --- pkg/core/statesync/mptpool.go | 5 ++++- pkg/core/statesync/mptpool_test.go | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pkg/core/statesync/mptpool.go b/pkg/core/statesync/mptpool.go index 93bbb41a4..819188246 100644 --- a/pkg/core/statesync/mptpool.go +++ b/pkg/core/statesync/mptpool.go @@ -37,7 +37,10 @@ func (mp *Pool) TryGet(hash util.Uint256) ([][]byte, bool) { defer mp.lock.RUnlock() paths, ok := mp.hashes[hash] - return paths, ok + // need to copy here, because we can modify existing array of paths inside the pool. + res := make([][]byte, len(paths)) + copy(res, paths) + return res, ok } // GetAll returns all MPT nodes with the corresponding paths from the pool. diff --git a/pkg/core/statesync/mptpool_test.go b/pkg/core/statesync/mptpool_test.go index bab32364b..2d094025c 100644 --- a/pkg/core/statesync/mptpool_test.go +++ b/pkg/core/statesync/mptpool_test.go @@ -1,6 +1,7 @@ package statesync import ( + "encoding/hex" "testing" "github.com/nspcc-dev/neo-go/internal/random" @@ -102,3 +103,21 @@ func TestPool_GetBatch(t *testing.T) { check(t, 5, 5) }) } + +func TestPool_UpdateUsingSliceFromPool(t *testing.T) { + mp := NewPool() + p1, _ := hex.DecodeString("0f0a0f0f0f0f0f0f0104020b02080c0a06050e070b050404060206060d07080602030b04040b050e040406030f0708060c05") + p2, _ := hex.DecodeString("0f0a0f0f0f0f0f0f01040a0b000f04000b03090b02090b0e040f0d0b060d070e0b0b090b0906080602060c0d0f0e0d04070e") + p3, _ := hex.DecodeString("0f0a0f0f0f0f0f0f01040b010d01080f050f000a0d0e08060c040b050800050904060f050807080a080c07040d0107080007") + h, _ := util.Uint256DecodeStringBE("57e197679ef031bf2f0b466b20afe3f67ac04dcff80a1dc4d12dd98dd21a2511") + mp.Add(h, p1) + mp.Add(h, p2) + mp.Add(h, p3) + + toBeRemoved, ok := mp.TryGet(h) + require.True(t, ok) + + mp.Update(map[util.Uint256][][]byte{h: toBeRemoved}, nil) + // test that all items were successfully removed. + require.Equal(t, 0, len(mp.GetAll())) +}