core/state: merge spent and unspent coins state, use it to store more things

This change reduces pressure on DB by doing the following things:
 * not storing additional KV pair for SpentCoin
 * storing Output right in the UnspentCoin, thus eliminating the need to get a
   full transaction from DB

At the same time it makes UnspentCoin more fat and hot, but it should probably
worth it.

Also drop `GetUnspentCoinStateOrNew` as it shouldn't ever existed, UTXOs
can't come out of nowhere.

1.5M block import time (VerifyBlocks disabled) on AMD Ryzen 5 1600/16GB/HDD,
before:
real    302m9.895s
user    96m17.200s
sys     13m37.084s

after:
real    159m16.551s
user    69m58.279s
sys     7m34.334s

So it's almost two-fold which is a great improvement.
This commit is contained in:
Roman Khimov 2020-03-09 18:56:24 +03:00
parent e1f194ea7b
commit 23464401bc
7 changed files with 117 additions and 278 deletions

View file

@ -94,14 +94,6 @@ func TestDeleteContractState(t *testing.T) {
require.Nil(t, gotContractState)
}
func TestGetUnspentCoinStateOrNew_New(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
hash := random.Uint256()
unspentCoinState, err := dao.GetUnspentCoinStateOrNew(hash)
require.NoError(t, err)
require.NotNil(t, unspentCoinState)
}
func TestGetUnspentCoinState_Err(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
hash := random.Uint256()
@ -113,7 +105,7 @@ func TestGetUnspentCoinState_Err(t *testing.T) {
func TestPutGetUnspentCoinState(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
hash := random.Uint256()
unspentCoinState := &state.UnspentCoin{States: []state.Coin{}}
unspentCoinState := &state.UnspentCoin{Height: 42, States: []state.OutputState{}}
err := dao.PutUnspentCoinState(hash, unspentCoinState)
require.NoError(t, err)
gotUnspentCoinState, err := dao.GetUnspentCoinState(hash)
@ -121,46 +113,6 @@ func TestPutGetUnspentCoinState(t *testing.T) {
require.Equal(t, unspentCoinState, gotUnspentCoinState)
}
func TestGetSpentCoinStateOrNew_New(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
hash := random.Uint256()
spentCoinState, err := dao.GetSpentCoinsOrNew(hash, 1)
require.NoError(t, err)
require.NotNil(t, spentCoinState)
}
func TestPutAndGetSpentCoinState(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
hash := random.Uint256()
spentCoinState := &state.SpentCoin{Items: make(map[uint16]uint32)}
err := dao.PutSpentCoinState(hash, spentCoinState)
require.NoError(t, err)
gotSpentCoinState, err := dao.GetSpentCoinState(hash)
require.NoError(t, err)
require.Equal(t, spentCoinState, gotSpentCoinState)
}
func TestGetSpentCoinState_Err(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
hash := random.Uint256()
spentCoinState, err := dao.GetSpentCoinState(hash)
require.Error(t, err)
require.Nil(t, spentCoinState)
}
func TestDeleteSpentCoinState(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
hash := random.Uint256()
spentCoinState := &state.SpentCoin{Items: make(map[uint16]uint32)}
err := dao.PutSpentCoinState(hash, spentCoinState)
require.NoError(t, err)
err = dao.DeleteSpentCoinState(hash)
require.NoError(t, err)
gotSpentCoinState, err := dao.GetSpentCoinState(hash)
require.Error(t, err)
require.Nil(t, gotSpentCoinState)
}
func TestGetValidatorStateOrNew_New(t *testing.T) {
dao := newDao(storage.NewMemoryStore())
publicKey := &keys.PublicKey{}