forked from TrueCloudLab/neoneo-go
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
|
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.
|
// LastBatch returns last persisted storage batch.
|
||||||
func (bc *Blockchain) LastBatch() *storage.MemBatch {
|
func (bc *Blockchain) LastBatch() *storage.MemBatch {
|
||||||
return bc.lastBatch
|
return bc.lastBatch
|
||||||
|
|
|
@ -35,6 +35,7 @@ type Blockchainer interface {
|
||||||
GetAssetState(util.Uint256) *state.Asset
|
GetAssetState(util.Uint256) *state.Asset
|
||||||
GetAccountState(util.Uint160) *state.Account
|
GetAccountState(util.Uint160) *state.Account
|
||||||
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
||||||
|
GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error)
|
||||||
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
||||||
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
||||||
GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error)
|
GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error)
|
||||||
|
|
|
@ -35,6 +35,7 @@ type DAO interface {
|
||||||
GetCurrentStateRootHeight() (uint32, error)
|
GetCurrentStateRootHeight() (uint32, error)
|
||||||
GetHeaderHashes() ([]util.Uint256, error)
|
GetHeaderHashes() ([]util.Uint256, error)
|
||||||
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
|
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
|
||||||
|
GetNEP5Metadata(h util.Uint160) (*state.NEP5Metadata, error)
|
||||||
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
|
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
|
||||||
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
||||||
PutStateRoot(root *state.MPTRootState) error
|
PutStateRoot(root *state.MPTRootState) error
|
||||||
|
@ -58,6 +59,7 @@ type DAO interface {
|
||||||
PutContractState(cs *state.Contract) error
|
PutContractState(cs *state.Contract) error
|
||||||
PutCurrentHeader(hashAndIndex []byte) error
|
PutCurrentHeader(hashAndIndex []byte) error
|
||||||
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) 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
|
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
|
||||||
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
|
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
|
||||||
PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) 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)
|
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.
|
// -- end contracts.
|
||||||
|
|
||||||
// -- start nep5 balances.
|
// -- 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/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"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/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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
gherr "github.com/pkg/errors"
|
gherr "github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -583,8 +585,8 @@ func (ic *interopContext) contractMigrate(v *vm.VM) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
hash := getContextScriptHash(v, 0)
|
||||||
if contract.HasStorage() {
|
if contract.HasStorage() {
|
||||||
hash := getContextScriptHash(v, 0)
|
|
||||||
siMap, err := ic.dao.GetStorageItems(hash, nil)
|
siMap, err := ic.dao.GetStorageItems(hash, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -598,6 +600,26 @@ func (ic *interopContext) contractMigrate(v *vm.VM) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ic.dao.MigrateNEP5Balances(hash, contract.ScriptHash())
|
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))
|
v.Estack().PushVal(vm.NewInteropItem(contract))
|
||||||
|
|
|
@ -49,6 +49,11 @@ type NEP5Balances struct {
|
||||||
NextTransferBatch uint32
|
NextTransferBatch uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEP5Metadata is a metadata for NEP5 contracts.
|
||||||
|
type NEP5Metadata struct {
|
||||||
|
Decimals int64
|
||||||
|
}
|
||||||
|
|
||||||
// NewNEP5Balances returns new NEP5Balances.
|
// NewNEP5Balances returns new NEP5Balances.
|
||||||
func NewNEP5Balances() *NEP5Balances {
|
func NewNEP5Balances() *NEP5Balances {
|
||||||
return &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.
|
// Append appends single transfer to a log.
|
||||||
func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
|
func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
|
|
|
@ -17,6 +17,7 @@ const (
|
||||||
STAsset KeyPrefix = 0x4c
|
STAsset KeyPrefix = 0x4c
|
||||||
STNotification KeyPrefix = 0x4d
|
STNotification KeyPrefix = 0x4d
|
||||||
STContract KeyPrefix = 0x50
|
STContract KeyPrefix = 0x50
|
||||||
|
STMigration KeyPrefix = 0x51
|
||||||
STStorage KeyPrefix = 0x70
|
STStorage KeyPrefix = 0x70
|
||||||
STNEP5Transfers KeyPrefix = 0x72
|
STNEP5Transfers KeyPrefix = 0x72
|
||||||
STNEP5Balances KeyPrefix = 0x73
|
STNEP5Balances KeyPrefix = 0x73
|
||||||
|
|
|
@ -93,6 +93,9 @@ func (chain testChain) GetAssetState(util.Uint256) *state.Asset {
|
||||||
func (chain testChain) GetAccountState(util.Uint160) *state.Account {
|
func (chain testChain) GetAccountState(util.Uint160) *state.Account {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
func (chain testChain) GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
func (chain testChain) GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog {
|
func (chain testChain) GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue