From 377fb382aab019f90056984afc34b85388db03a0 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 9 Mar 2020 16:56:37 +0300 Subject: [PATCH] core: move (un)SpentCoin structs into the state package As they're all about the state. --- pkg/core/blockchain.go | 20 +++---- pkg/core/blockchainer.go | 2 +- pkg/core/dao.go | 26 ++++----- pkg/core/dao_test.go | 6 +- pkg/core/spent_coin.go | 10 ++++ pkg/core/spent_coin_state.go | 56 ------------------- pkg/core/state/spent_coin.go | 46 +++++++++++++++ .../spent_coin_test.go} | 13 ++--- pkg/core/state/unspent_coin.go | 38 +++++++++++++ pkg/core/state/unspent_coin_test.go | 28 ++++++++++ pkg/core/unspent_coin_state.go | 39 ------------- pkg/core/unspent_coint_state_test.go | 29 ---------- pkg/network/helper_test.go | 3 +- 13 files changed, 155 insertions(+), 161 deletions(-) create mode 100644 pkg/core/spent_coin.go delete mode 100644 pkg/core/spent_coin_state.go create mode 100644 pkg/core/state/spent_coin.go rename pkg/core/{spent_coin_state_test.go => state/spent_coin_test.go} (61%) create mode 100644 pkg/core/state/unspent_coin.go create mode 100644 pkg/core/state/unspent_coin_test.go delete mode 100644 pkg/core/unspent_coin_state.go delete mode 100644 pkg/core/unspent_coint_state_test.go diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index bfff6e60f..d7bfc42e2 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -475,7 +475,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { return err } - if err := cache.PutUnspentCoinState(tx.Hash(), NewUnspentCoinState(len(tx.Outputs))); err != nil { + if err := cache.PutUnspentCoinState(tx.Hash(), state.NewUnspentCoin(len(tx.Outputs))); err != nil { return err } @@ -499,9 +499,9 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { if err != nil { return err } - oldSpentCoinLen := len(spentCoin.items) + oldSpentCoinLen := len(spentCoin.Items) for _, input := range inputs { - unspent.states[input.PrevIndex] = state.CoinSpent + unspent.States[input.PrevIndex] = state.CoinSpent prevTXOutput := prevTX.Outputs[input.PrevIndex] account, err := cache.GetAccountStateOrNew(prevTXOutput.ScriptHash) if err != nil { @@ -516,7 +516,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { End: block.Index, Value: prevTXOutput.Amount, }) - spentCoin.items[input.PrevIndex] = block.Index + spentCoin.Items[input.PrevIndex] = block.Index if err = processTXWithValidatorsSubtract(&prevTXOutput, account, cache); err != nil { return err } @@ -548,7 +548,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { if err = cache.PutUnspentCoinState(prevHash, unspent); err != nil { return err } - if oldSpentCoinLen != len(spentCoin.items) { + if oldSpentCoinLen != len(spentCoin.Items) { if err = cache.PutSpentCoinState(prevHash, spentCoin); err != nil { return err } @@ -590,7 +590,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { for _, input := range t.Claims { scs, err := cache.GetSpentCoinState(input.PrevHash) if err == nil { - _, ok := scs.items[input.PrevIndex] + _, ok := scs.Items[input.PrevIndex] if !ok { err = errors.New("no spent coin state") } @@ -644,8 +644,8 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { return err } - delete(scs.items, input.PrevIndex) - if len(scs.items) > 0 { + delete(scs.Items, input.PrevIndex) + if len(scs.Items) > 0 { if err = cache.PutSpentCoinState(input.PrevHash, scs); err != nil { return err } @@ -1174,7 +1174,7 @@ func (bc *Blockchain) GetAccountState(scriptHash util.Uint160) *state.Account { } // GetUnspentCoinState returns unspent coin state for given tx hash. -func (bc *Blockchain) GetUnspentCoinState(hash util.Uint256) *UnspentCoinState { +func (bc *Blockchain) GetUnspentCoinState(hash util.Uint256) *state.UnspentCoin { ucs, err := bc.dao.GetUnspentCoinState(hash) if ucs == nil && err != storage.ErrKeyNotFound { bc.log.Warn("failed to get unspent coin state", zap.Error(err)) @@ -1472,7 +1472,7 @@ func (bc *Blockchain) getUnclaimed(h util.Uint256) (map[uint16]*spentCoin, error } result := make(map[uint16]*spentCoin) - for i, height := range scs.items { + for i, height := range scs.Items { result[i] = &spentCoin{ Output: &tx.Outputs[i], StartHeight: txHeight, diff --git a/pkg/core/blockchainer.go b/pkg/core/blockchainer.go index 0c2aa0065..eb10527ca 100644 --- a/pkg/core/blockchainer.go +++ b/pkg/core/blockchainer.go @@ -41,7 +41,7 @@ type Blockchainer interface { GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error) GetTestVM() (*vm.VM, storage.Store) GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error) - GetUnspentCoinState(util.Uint256) *UnspentCoinState + GetUnspentCoinState(util.Uint256) *state.UnspentCoin References(t *transaction.Transaction) ([]transaction.InOut, error) mempool.Feer // fee interface PoolTx(*transaction.Transaction) error diff --git a/pkg/core/dao.go b/pkg/core/dao.go index 4973a3b76..fbab4c6ef 100644 --- a/pkg/core/dao.go +++ b/pkg/core/dao.go @@ -178,22 +178,20 @@ func (dao *dao) AppendNEP5Transfer(acc util.Uint160, tr *state.NEP5Transfer) err // GetUnspentCoinStateOrNew gets UnspentCoinState from temporary or persistent Store // and return it. If it's not present in both stores, returns a new // UnspentCoinState. -func (dao *dao) GetUnspentCoinStateOrNew(hash util.Uint256) (*UnspentCoinState, error) { +func (dao *dao) GetUnspentCoinStateOrNew(hash util.Uint256) (*state.UnspentCoin, error) { unspent, err := dao.GetUnspentCoinState(hash) if err != nil { if err != storage.ErrKeyNotFound { return nil, err } - unspent = &UnspentCoinState{ - states: []state.Coin{}, - } + unspent = state.NewUnspentCoin(0) } return unspent, nil } // GetUnspentCoinState retrieves UnspentCoinState from the given store. -func (dao *dao) GetUnspentCoinState(hash util.Uint256) (*UnspentCoinState, error) { - unspent := &UnspentCoinState{} +func (dao *dao) GetUnspentCoinState(hash util.Uint256) (*state.UnspentCoin, error) { + unspent := &state.UnspentCoin{} key := storage.AppendPrefix(storage.STCoin, hash.BytesLE()) err := dao.GetAndDecode(unspent, key) if err != nil { @@ -203,7 +201,7 @@ func (dao *dao) GetUnspentCoinState(hash util.Uint256) (*UnspentCoinState, error } // PutUnspentCoinState puts given UnspentCoinState into the given store. -func (dao *dao) PutUnspentCoinState(hash util.Uint256, ucs *UnspentCoinState) error { +func (dao *dao) PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) error { key := storage.AppendPrefix(storage.STCoin, hash.BytesLE()) return dao.Put(ucs, key) } @@ -213,20 +211,20 @@ func (dao *dao) PutUnspentCoinState(hash util.Uint256, ucs *UnspentCoinState) er // -- start spent coins. // GetSpentCoinsOrNew returns spent coins from store. -func (dao *dao) GetSpentCoinsOrNew(hash util.Uint256, height uint32) (*SpentCoinState, error) { +func (dao *dao) GetSpentCoinsOrNew(hash util.Uint256, height uint32) (*state.SpentCoin, error) { spent, err := dao.GetSpentCoinState(hash) if err != nil { if err != storage.ErrKeyNotFound { return nil, err } - spent = NewSpentCoinState(height) + spent = state.NewSpentCoin(height) } return spent, nil } // GetSpentCoinState gets SpentCoinState from the given store. -func (dao *dao) GetSpentCoinState(hash util.Uint256) (*SpentCoinState, error) { - spent := &SpentCoinState{} +func (dao *dao) GetSpentCoinState(hash util.Uint256) (*state.SpentCoin, error) { + spent := &state.SpentCoin{} key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesLE()) err := dao.GetAndDecode(spent, key) if err != nil { @@ -236,7 +234,7 @@ func (dao *dao) GetSpentCoinState(hash util.Uint256) (*SpentCoinState, error) { } // PutSpentCoinState puts given SpentCoinState into the given store. -func (dao *dao) PutSpentCoinState(hash util.Uint256, scs *SpentCoinState) error { +func (dao *dao) PutSpentCoinState(hash util.Uint256, scs *state.SpentCoin) error { key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesLE()) return dao.Put(scs, key) } @@ -592,7 +590,7 @@ func (dao *dao) IsDoubleSpend(tx *transaction.Transaction) bool { return false } for _, input := range inputs { - if int(input.PrevIndex) >= len(unspent.states) || unspent.states[input.PrevIndex] == state.CoinSpent { + if int(input.PrevIndex) >= len(unspent.States) || unspent.States[input.PrevIndex] == state.CoinSpent { return true } } @@ -612,7 +610,7 @@ func (dao *dao) IsDoubleClaim(claim *transaction.ClaimTX) bool { return true } for _, input := range inputs { - _, ok := scs.items[input.PrevIndex] + _, ok := scs.Items[input.PrevIndex] if !ok { return true } diff --git a/pkg/core/dao_test.go b/pkg/core/dao_test.go index a854265ff..962d16df0 100644 --- a/pkg/core/dao_test.go +++ b/pkg/core/dao_test.go @@ -113,7 +113,7 @@ func TestGetUnspentCoinState_Err(t *testing.T) { func TestPutGetUnspentCoinState(t *testing.T) { dao := newDao(storage.NewMemoryStore()) hash := random.Uint256() - unspentCoinState := &UnspentCoinState{states: []state.Coin{}} + unspentCoinState := &state.UnspentCoin{States: []state.Coin{}} err := dao.PutUnspentCoinState(hash, unspentCoinState) require.NoError(t, err) gotUnspentCoinState, err := dao.GetUnspentCoinState(hash) @@ -132,7 +132,7 @@ func TestGetSpentCoinStateOrNew_New(t *testing.T) { func TestPutAndGetSpentCoinState(t *testing.T) { dao := newDao(storage.NewMemoryStore()) hash := random.Uint256() - spentCoinState := &SpentCoinState{items: make(map[uint16]uint32)} + spentCoinState := &state.SpentCoin{Items: make(map[uint16]uint32)} err := dao.PutSpentCoinState(hash, spentCoinState) require.NoError(t, err) gotSpentCoinState, err := dao.GetSpentCoinState(hash) @@ -151,7 +151,7 @@ func TestGetSpentCoinState_Err(t *testing.T) { func TestDeleteSpentCoinState(t *testing.T) { dao := newDao(storage.NewMemoryStore()) hash := random.Uint256() - spentCoinState := &SpentCoinState{items: make(map[uint16]uint32)} + spentCoinState := &state.SpentCoin{Items: make(map[uint16]uint32)} err := dao.PutSpentCoinState(hash, spentCoinState) require.NoError(t, err) err = dao.DeleteSpentCoinState(hash) diff --git a/pkg/core/spent_coin.go b/pkg/core/spent_coin.go new file mode 100644 index 000000000..9d42cb8af --- /dev/null +++ b/pkg/core/spent_coin.go @@ -0,0 +1,10 @@ +package core + +import "github.com/nspcc-dev/neo-go/pkg/core/transaction" + +// spentCoin represents the state of a single spent coin output. +type spentCoin struct { + Output *transaction.Output + StartHeight uint32 + EndHeight uint32 +} diff --git a/pkg/core/spent_coin_state.go b/pkg/core/spent_coin_state.go deleted file mode 100644 index 85f0e4008..000000000 --- a/pkg/core/spent_coin_state.go +++ /dev/null @@ -1,56 +0,0 @@ -package core - -import ( - "github.com/nspcc-dev/neo-go/pkg/core/transaction" - "github.com/nspcc-dev/neo-go/pkg/io" -) - -// SpentCoinState represents the state of a spent coin. -type SpentCoinState struct { - txHeight uint32 - - // A mapping between the index of the prevIndex and block height. - items map[uint16]uint32 -} - -// spentCoin represents the state of a single spent coin output. -type spentCoin struct { - Output *transaction.Output - StartHeight uint32 - EndHeight uint32 -} - -// NewSpentCoinState returns a new SpentCoinState object. -func NewSpentCoinState(height uint32) *SpentCoinState { - return &SpentCoinState{ - txHeight: height, - items: make(map[uint16]uint32), - } -} - -// DecodeBinary implements Serializable interface. -func (s *SpentCoinState) DecodeBinary(br *io.BinReader) { - s.txHeight = br.ReadU32LE() - - s.items = make(map[uint16]uint32) - lenItems := br.ReadVarUint() - for i := 0; i < int(lenItems); i++ { - var ( - key uint16 - value uint32 - ) - key = br.ReadU16LE() - value = br.ReadU32LE() - s.items[key] = value - } -} - -// EncodeBinary implements Serializable interface. -func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) { - bw.WriteU32LE(s.txHeight) - bw.WriteVarUint(uint64(len(s.items))) - for k, v := range s.items { - bw.WriteU16LE(k) - bw.WriteU32LE(v) - } -} diff --git a/pkg/core/state/spent_coin.go b/pkg/core/state/spent_coin.go new file mode 100644 index 000000000..d1f2c3553 --- /dev/null +++ b/pkg/core/state/spent_coin.go @@ -0,0 +1,46 @@ +package state + +import "github.com/nspcc-dev/neo-go/pkg/io" + +// SpentCoin represents the state of a spent coin. +type SpentCoin struct { + TxHeight uint32 + + // A mapping between the index of the prevIndex and block height. + Items map[uint16]uint32 +} + +// NewSpentCoin returns a new SpentCoin object. +func NewSpentCoin(height uint32) *SpentCoin { + return &SpentCoin{ + TxHeight: height, + Items: make(map[uint16]uint32), + } +} + +// DecodeBinary implements Serializable interface. +func (s *SpentCoin) DecodeBinary(br *io.BinReader) { + s.TxHeight = br.ReadU32LE() + + s.Items = make(map[uint16]uint32) + lenItems := br.ReadVarUint() + for i := 0; i < int(lenItems); i++ { + var ( + key uint16 + value uint32 + ) + key = br.ReadU16LE() + value = br.ReadU32LE() + s.Items[key] = value + } +} + +// EncodeBinary implements Serializable interface. +func (s *SpentCoin) EncodeBinary(bw *io.BinWriter) { + bw.WriteU32LE(s.TxHeight) + bw.WriteVarUint(uint64(len(s.Items))) + for k, v := range s.Items { + bw.WriteU16LE(k) + bw.WriteU32LE(v) + } +} diff --git a/pkg/core/spent_coin_state_test.go b/pkg/core/state/spent_coin_test.go similarity index 61% rename from pkg/core/spent_coin_state_test.go rename to pkg/core/state/spent_coin_test.go index 4fce2b386..8759a9ba3 100644 --- a/pkg/core/spent_coin_state_test.go +++ b/pkg/core/state/spent_coin_test.go @@ -1,17 +1,16 @@ -package core +package state import ( "testing" - "github.com/nspcc-dev/neo-go/pkg/internal/random" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) -func TestEncodeDecodeSpentCoinState(t *testing.T) { - spent := &SpentCoinState{ - txHeight: 1001, - items: map[uint16]uint32{ +func TestEncodeDecodeSpentCoin(t *testing.T) { + spent := &SpentCoin{ + TxHeight: 1001, + Items: map[uint16]uint32{ 1: 3, 2: 8, 4: 100, @@ -21,7 +20,7 @@ func TestEncodeDecodeSpentCoinState(t *testing.T) { buf := io.NewBufBinWriter() spent.EncodeBinary(buf.BinWriter) assert.Nil(t, buf.Err) - spentDecode := new(SpentCoinState) + spentDecode := new(SpentCoin) r := io.NewBinReaderFromBuf(buf.Bytes()) spentDecode.DecodeBinary(r) assert.Nil(t, r.Err) diff --git a/pkg/core/state/unspent_coin.go b/pkg/core/state/unspent_coin.go new file mode 100644 index 000000000..d153ef639 --- /dev/null +++ b/pkg/core/state/unspent_coin.go @@ -0,0 +1,38 @@ +package state + +import ( + "github.com/nspcc-dev/neo-go/pkg/io" +) + +// UnspentCoin hold the state of a unspent coin. +type UnspentCoin struct { + States []Coin +} + +// NewUnspentCoin returns a new unspent coin state with N confirmed states. +func NewUnspentCoin(n int) *UnspentCoin { + u := &UnspentCoin{ + States: make([]Coin, n), + } + for i := 0; i < n; i++ { + u.States[i] = CoinConfirmed + } + return u +} + +// EncodeBinary encodes UnspentCoin to the given BinWriter. +func (s *UnspentCoin) EncodeBinary(bw *io.BinWriter) { + bw.WriteVarUint(uint64(len(s.States))) + for _, state := range s.States { + bw.WriteB(byte(state)) + } +} + +// DecodeBinary decodes UnspentCoin from the given BinReader. +func (s *UnspentCoin) DecodeBinary(br *io.BinReader) { + lenStates := br.ReadVarUint() + s.States = make([]Coin, lenStates) + for i := 0; i < int(lenStates); i++ { + s.States[i] = Coin(br.ReadB()) + } +} diff --git a/pkg/core/state/unspent_coin_test.go b/pkg/core/state/unspent_coin_test.go new file mode 100644 index 000000000..85f82e331 --- /dev/null +++ b/pkg/core/state/unspent_coin_test.go @@ -0,0 +1,28 @@ +package state + +import ( + "testing" + + "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/stretchr/testify/assert" +) + +func TestDecodeEncodeUnspentCoin(t *testing.T) { + unspent := &UnspentCoin{ + States: []Coin{ + CoinConfirmed, + CoinSpent, + CoinSpent, + CoinSpent, + CoinConfirmed, + }, + } + + buf := io.NewBufBinWriter() + unspent.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) + unspentDecode := &UnspentCoin{} + r := io.NewBinReaderFromBuf(buf.Bytes()) + unspentDecode.DecodeBinary(r) + assert.Nil(t, r.Err) +} diff --git a/pkg/core/unspent_coin_state.go b/pkg/core/unspent_coin_state.go deleted file mode 100644 index cbcd6a2e8..000000000 --- a/pkg/core/unspent_coin_state.go +++ /dev/null @@ -1,39 +0,0 @@ -package core - -import ( - "github.com/nspcc-dev/neo-go/pkg/core/state" - "github.com/nspcc-dev/neo-go/pkg/io" -) - -// UnspentCoinState hold the state of a unspent coin. -type UnspentCoinState struct { - states []state.Coin -} - -// NewUnspentCoinState returns a new unspent coin state with N confirmed states. -func NewUnspentCoinState(n int) *UnspentCoinState { - u := &UnspentCoinState{ - states: make([]state.Coin, n), - } - for i := 0; i < n; i++ { - u.states[i] = state.CoinConfirmed - } - return u -} - -// EncodeBinary encodes UnspentCoinState to the given BinWriter. -func (s *UnspentCoinState) EncodeBinary(bw *io.BinWriter) { - bw.WriteVarUint(uint64(len(s.states))) - for _, state := range s.states { - bw.WriteB(byte(state)) - } -} - -// DecodeBinary decodes UnspentCoinState from the given BinReader. -func (s *UnspentCoinState) DecodeBinary(br *io.BinReader) { - lenStates := br.ReadVarUint() - s.states = make([]state.Coin, lenStates) - for i := 0; i < int(lenStates); i++ { - s.states[i] = state.Coin(br.ReadB()) - } -} diff --git a/pkg/core/unspent_coint_state_test.go b/pkg/core/unspent_coint_state_test.go deleted file mode 100644 index 98e089f58..000000000 --- a/pkg/core/unspent_coint_state_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package core - -import ( - "testing" - - "github.com/nspcc-dev/neo-go/pkg/core/state" - "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/stretchr/testify/assert" -) - -func TestDecodeEncodeUnspentCoinState(t *testing.T) { - unspent := &UnspentCoinState{ - states: []state.Coin{ - state.CoinConfirmed, - state.CoinSpent, - state.CoinSpent, - state.CoinSpent, - state.CoinConfirmed, - }, - } - - buf := io.NewBufBinWriter() - unspent.EncodeBinary(buf.BinWriter) - assert.Nil(t, buf.Err) - unspentDecode := &UnspentCoinState{} - r := io.NewBinReaderFromBuf(buf.Bytes()) - unspentDecode.DecodeBinary(r) - assert.Nil(t, r.Err) -} diff --git a/pkg/network/helper_test.go b/pkg/network/helper_test.go index ff2edbc4b..28df85ad3 100644 --- a/pkg/network/helper_test.go +++ b/pkg/network/helper_test.go @@ -8,7 +8,6 @@ import ( "time" "github.com/nspcc-dev/neo-go/config" - "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/mempool" "github.com/nspcc-dev/neo-go/pkg/core/state" @@ -126,7 +125,7 @@ func (chain testChain) GetTransaction(util.Uint256) (*transaction.Transaction, u panic("TODO") } -func (chain testChain) GetUnspentCoinState(util.Uint256) *core.UnspentCoinState { +func (chain testChain) GetUnspentCoinState(util.Uint256) *state.UnspentCoin { panic("TODO") }