mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-12 11:10:35 +00:00
core,dao: save contract metadata on migration
After contract is migrated there is no way to retrieve it's state. This commit implements some metadata for NEP5 contracts, so that values important for diplaying transfer log aren't lost.
This commit is contained in:
parent
7bdbfbad19
commit
7cd1bca1e1
7 changed files with 67 additions and 1 deletions
|
@ -994,6 +994,12 @@ func (bc *Blockchain) GetNEP5Balances(acc util.Uint160) *state.NEP5Balances {
|
|||
return bs
|
||||
}
|
||||
|
||||
// GetNEP5Metadata returns NEP5 metadata for the contract h.
|
||||
// Note: it is currently saved only for migrated contracts.
|
||||
func (bc *Blockchain) GetNEP5Metadata(h util.Uint160) (*state.NEP5Metadata, error) {
|
||||
return bc.dao.GetNEP5Metadata(h)
|
||||
}
|
||||
|
||||
// LastBatch returns last persisted storage batch.
|
||||
func (bc *Blockchain) LastBatch() *storage.MemBatch {
|
||||
return bc.lastBatch
|
||||
|
|
|
@ -35,6 +35,7 @@ type Blockchainer interface {
|
|||
GetAssetState(util.Uint256) *state.Asset
|
||||
GetAccountState(util.Uint160) *state.Account
|
||||
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
||||
GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error)
|
||||
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
||||
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
||||
GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error)
|
||||
|
|
|
@ -35,6 +35,7 @@ type DAO interface {
|
|||
GetCurrentStateRootHeight() (uint32, error)
|
||||
GetHeaderHashes() ([]util.Uint256, error)
|
||||
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
|
||||
GetNEP5Metadata(h util.Uint160) (*state.NEP5Metadata, error)
|
||||
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
|
||||
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
||||
PutStateRoot(root *state.MPTRootState) error
|
||||
|
@ -58,6 +59,7 @@ type DAO interface {
|
|||
PutContractState(cs *state.Contract) error
|
||||
PutCurrentHeader(hashAndIndex []byte) error
|
||||
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
|
||||
PutNEP5Metadata(h util.Uint160, meta *state.NEP5Metadata) error
|
||||
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
|
||||
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
|
||||
PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) error
|
||||
|
@ -215,6 +217,22 @@ func (dao *Simple) DeleteContractState(hash util.Uint160) error {
|
|||
return dao.Store.Delete(key)
|
||||
}
|
||||
|
||||
// GetNEP5Metadata returns saved NEP5 metadata for the contract h.
|
||||
func (dao *Simple) GetNEP5Metadata(h util.Uint160) (*state.NEP5Metadata, error) {
|
||||
key := storage.AppendPrefix(storage.STMigration, h.BytesBE())
|
||||
m := new(state.NEP5Metadata)
|
||||
if err := dao.GetAndDecode(m, key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// PutNEP5Metadata saves NEP5 metadata for the contract h.
|
||||
func (dao *Simple) PutNEP5Metadata(h util.Uint160, m *state.NEP5Metadata) error {
|
||||
key := storage.AppendPrefix(storage.STMigration, h.BytesBE())
|
||||
return dao.Put(m, key)
|
||||
}
|
||||
|
||||
// -- end contracts.
|
||||
|
||||
// -- start nep5 balances.
|
||||
|
|
|
@ -12,10 +12,12 @@ import (
|
|||
"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/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"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"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
gherr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -583,8 +585,8 @@ func (ic *interopContext) contractMigrate(v *vm.VM) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash := getContextScriptHash(v, 0)
|
||||
if contract.HasStorage() {
|
||||
hash := getContextScriptHash(v, 0)
|
||||
siMap, err := ic.dao.GetStorageItems(hash, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -598,6 +600,26 @@ func (ic *interopContext) contractMigrate(v *vm.VM) error {
|
|||
}
|
||||
}
|
||||
ic.dao.MigrateNEP5Balances(hash, contract.ScriptHash())
|
||||
|
||||
// save NEP5 metadata if any
|
||||
v := ic.bc.GetTestVM()
|
||||
w := io.NewBufBinWriter()
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, hash, "decimals")
|
||||
v.SetGasLimit(ic.bc.GetConfig().FreeGasLimit)
|
||||
v.Load(w.Bytes())
|
||||
if err := v.Run(); err == nil && v.Estack().Len() == 1 {
|
||||
res := v.Estack().Pop().Item().ToContractParameter(map[vm.StackItem]bool{})
|
||||
d := int64(-1)
|
||||
switch res.Type {
|
||||
case smartcontract.IntegerType:
|
||||
d = res.Value.(int64)
|
||||
case smartcontract.ByteArrayType:
|
||||
d = emit.BytesToInt(res.Value.([]byte)).Int64()
|
||||
}
|
||||
if d >= 0 {
|
||||
ic.dao.PutNEP5Metadata(hash, &state.NEP5Metadata{Decimals: d})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v.Estack().PushVal(vm.NewInteropItem(contract))
|
||||
|
|
|
@ -49,6 +49,11 @@ type NEP5Balances struct {
|
|||
NextTransferBatch uint32
|
||||
}
|
||||
|
||||
// NEP5Metadata is a metadata for NEP5 contracts.
|
||||
type NEP5Metadata struct {
|
||||
Decimals int64
|
||||
}
|
||||
|
||||
// NewNEP5Balances returns new NEP5Balances.
|
||||
func NewNEP5Balances() *NEP5Balances {
|
||||
return &NEP5Balances{
|
||||
|
@ -81,6 +86,16 @@ func (bs *NEP5Balances) EncodeBinary(w *io.BinWriter) {
|
|||
}
|
||||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
func (bs *NEP5Metadata) DecodeBinary(r *io.BinReader) {
|
||||
bs.Decimals = int64(r.ReadU64LE())
|
||||
}
|
||||
|
||||
// EncodeBinary implements io.Serializable interface.
|
||||
func (bs *NEP5Metadata) EncodeBinary(w *io.BinWriter) {
|
||||
w.WriteU64LE(uint64(bs.Decimals))
|
||||
}
|
||||
|
||||
// Append appends single transfer to a log.
|
||||
func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
|
||||
w := io.NewBufBinWriter()
|
||||
|
|
|
@ -17,6 +17,7 @@ const (
|
|||
STAsset KeyPrefix = 0x4c
|
||||
STNotification KeyPrefix = 0x4d
|
||||
STContract KeyPrefix = 0x50
|
||||
STMigration KeyPrefix = 0x51
|
||||
STStorage KeyPrefix = 0x70
|
||||
STNEP5Transfers KeyPrefix = 0x72
|
||||
STNEP5Balances KeyPrefix = 0x73
|
||||
|
|
|
@ -93,6 +93,9 @@ func (chain testChain) GetAssetState(util.Uint256) *state.Asset {
|
|||
func (chain testChain) GetAccountState(util.Uint160) *state.Account {
|
||||
panic("TODO")
|
||||
}
|
||||
func (chain testChain) GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error) {
|
||||
panic("TODO")
|
||||
}
|
||||
func (chain testChain) GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog {
|
||||
panic("TODO")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue