forked from TrueCloudLab/neoneo-go
Merge pull request #1077 from nspcc-dev/neo3/smartcontract/id
core: store smartcontract items by id
This commit is contained in:
commit
36a65e3847
12 changed files with 168 additions and 140 deletions
|
@ -869,13 +869,13 @@ func (bc *Blockchain) GetAppExecResult(hash util.Uint256) (*state.AppExecResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageItem returns an item from storage.
|
// GetStorageItem returns an item from storage.
|
||||||
func (bc *Blockchain) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
func (bc *Blockchain) GetStorageItem(id int32, key []byte) *state.StorageItem {
|
||||||
return bc.dao.GetStorageItem(scripthash, key)
|
return bc.dao.GetStorageItem(id, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageItems returns all storage items for a given scripthash.
|
// GetStorageItems returns all storage items for a given contract id.
|
||||||
func (bc *Blockchain) GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error) {
|
func (bc *Blockchain) GetStorageItems(id int32) (map[string]*state.StorageItem, error) {
|
||||||
return bc.dao.GetStorageItems(hash)
|
return bc.dao.GetStorageItems(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlock returns a Block by the given hash.
|
// GetBlock returns a Block by the given hash.
|
||||||
|
|
|
@ -39,8 +39,8 @@ type Blockchainer interface {
|
||||||
GetValidators() ([]*keys.PublicKey, error)
|
GetValidators() ([]*keys.PublicKey, error)
|
||||||
GetStandByValidators() (keys.PublicKeys, error)
|
GetStandByValidators() (keys.PublicKeys, error)
|
||||||
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
||||||
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
GetStorageItem(id int32, key []byte) *state.StorageItem
|
||||||
GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error)
|
GetStorageItems(id int32) (map[string]*state.StorageItem, error)
|
||||||
GetTestVM(tx *transaction.Transaction) *vm.VM
|
GetTestVM(tx *transaction.Transaction) *vm.VM
|
||||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||||
mempool.Feer // fee interface
|
mempool.Feer // fee interface
|
||||||
|
|
|
@ -114,29 +114,29 @@ func TestCachedCachedDao(t *testing.T) {
|
||||||
assert.NotEqual(t, pdao.Store, intDao.Store)
|
assert.NotEqual(t, pdao.Store, intDao.Store)
|
||||||
assert.NotEqual(t, cdaoDao.Store, intDao.Store)
|
assert.NotEqual(t, cdaoDao.Store, intDao.Store)
|
||||||
|
|
||||||
hash := random.Uint160()
|
id := int32(random.Int(0, 1024))
|
||||||
key := []byte("qwerty")
|
key := []byte("qwerty")
|
||||||
si := &state.StorageItem{Value: []byte("poiuyt")}
|
si := &state.StorageItem{Value: []byte("poiuyt")}
|
||||||
require.NoError(t, ccdao.PutStorageItem(hash, key, si))
|
require.NoError(t, ccdao.PutStorageItem(id, key, si))
|
||||||
resi := ccdao.GetStorageItem(hash, key)
|
resi := ccdao.GetStorageItem(id, key)
|
||||||
assert.Equal(t, si, resi)
|
assert.Equal(t, si, resi)
|
||||||
|
|
||||||
resi = cdao.GetStorageItem(hash, key)
|
resi = cdao.GetStorageItem(id, key)
|
||||||
assert.Equal(t, (*state.StorageItem)(nil), resi)
|
assert.Equal(t, (*state.StorageItem)(nil), resi)
|
||||||
resi = pdao.GetStorageItem(hash, key)
|
resi = pdao.GetStorageItem(id, key)
|
||||||
assert.Equal(t, (*state.StorageItem)(nil), resi)
|
assert.Equal(t, (*state.StorageItem)(nil), resi)
|
||||||
|
|
||||||
cnt, err := ccdao.Persist()
|
cnt, err := ccdao.Persist()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, cnt)
|
assert.Equal(t, 1, cnt)
|
||||||
resi = cdao.GetStorageItem(hash, key)
|
resi = cdao.GetStorageItem(id, key)
|
||||||
assert.Equal(t, si, resi)
|
assert.Equal(t, si, resi)
|
||||||
resi = pdao.GetStorageItem(hash, key)
|
resi = pdao.GetStorageItem(id, key)
|
||||||
assert.Equal(t, (*state.StorageItem)(nil), resi)
|
assert.Equal(t, (*state.StorageItem)(nil), resi)
|
||||||
|
|
||||||
cnt, err = cdao.Persist()
|
cnt, err = cdao.Persist()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, cnt)
|
assert.Equal(t, 1, cnt)
|
||||||
resi = pdao.GetStorageItem(hash, key)
|
resi = pdao.GetStorageItem(id, key)
|
||||||
assert.Equal(t, si, resi)
|
assert.Equal(t, si, resi)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
type DAO interface {
|
type DAO interface {
|
||||||
AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error)
|
AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error)
|
||||||
DeleteContractState(hash util.Uint160) error
|
DeleteContractState(hash util.Uint160) error
|
||||||
DeleteStorageItem(scripthash util.Uint160, key []byte) error
|
DeleteStorageItem(id int32, key []byte) error
|
||||||
GetAccountState(hash util.Uint160) (*state.Account, error)
|
GetAccountState(hash util.Uint160) (*state.Account, error)
|
||||||
GetAccountStateOrNew(hash util.Uint160) (*state.Account, error)
|
GetAccountStateOrNew(hash util.Uint160) (*state.Account, error)
|
||||||
GetAndDecode(entity io.Serializable, key []byte) error
|
GetAndDecode(entity io.Serializable, key []byte) error
|
||||||
|
@ -33,9 +33,9 @@ type DAO interface {
|
||||||
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
|
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
|
||||||
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
|
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
|
||||||
GetNextContractID() (int32, error)
|
GetNextContractID() (int32, error)
|
||||||
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
GetStorageItem(id int32, key []byte) *state.StorageItem
|
||||||
GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error)
|
GetStorageItems(id int32) (map[string]*state.StorageItem, error)
|
||||||
GetStorageItemsWithPrefix(hash util.Uint160, prefix []byte) (map[string]*state.StorageItem, error)
|
GetStorageItemsWithPrefix(id int32, prefix []byte) (map[string]*state.StorageItem, error)
|
||||||
GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error)
|
GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error)
|
||||||
GetVersion() (string, error)
|
GetVersion() (string, error)
|
||||||
GetWrapped() DAO
|
GetWrapped() DAO
|
||||||
|
@ -48,7 +48,7 @@ type DAO interface {
|
||||||
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
|
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
|
||||||
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
|
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
|
||||||
PutNextContractID(id int32) error
|
PutNextContractID(id int32) error
|
||||||
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
|
PutStorageItem(id int32, key []byte, si *state.StorageItem) error
|
||||||
PutVersion(v string) error
|
PutVersion(v string) error
|
||||||
StoreAsBlock(block *block.Block) error
|
StoreAsBlock(block *block.Block) error
|
||||||
StoreAsCurrentBlock(block *block.Block) error
|
StoreAsCurrentBlock(block *block.Block) error
|
||||||
|
@ -296,8 +296,8 @@ func (dao *Simple) PutAppExecResult(aer *state.AppExecResult) error {
|
||||||
// -- start storage item.
|
// -- start storage item.
|
||||||
|
|
||||||
// GetStorageItem returns StorageItem if it exists in the given store.
|
// GetStorageItem returns StorageItem if it exists in the given store.
|
||||||
func (dao *Simple) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
func (dao *Simple) GetStorageItem(id int32, key []byte) *state.StorageItem {
|
||||||
b, err := dao.Store.Get(makeStorageItemKey(scripthash, key))
|
b, err := dao.Store.Get(makeStorageItemKey(id, key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -312,30 +312,30 @@ func (dao *Simple) GetStorageItem(scripthash util.Uint160, key []byte) *state.St
|
||||||
return si
|
return si
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutStorageItem puts given StorageItem for given script with given
|
// PutStorageItem puts given StorageItem for given id with given
|
||||||
// key into the given store.
|
// key into the given store.
|
||||||
func (dao *Simple) PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error {
|
func (dao *Simple) PutStorageItem(id int32, key []byte, si *state.StorageItem) error {
|
||||||
return dao.Put(si, makeStorageItemKey(scripthash, key))
|
return dao.Put(si, makeStorageItemKey(id, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteStorageItem drops storage item for the given script with the
|
// DeleteStorageItem drops storage item for the given id with the
|
||||||
// given key from the store.
|
// given key from the store.
|
||||||
func (dao *Simple) DeleteStorageItem(scripthash util.Uint160, key []byte) error {
|
func (dao *Simple) DeleteStorageItem(id int32, key []byte) error {
|
||||||
return dao.Store.Delete(makeStorageItemKey(scripthash, key))
|
return dao.Store.Delete(makeStorageItemKey(id, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageItems returns all storage items for a given scripthash.
|
// GetStorageItems returns all storage items for a given id.
|
||||||
func (dao *Simple) GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error) {
|
func (dao *Simple) GetStorageItems(id int32) (map[string]*state.StorageItem, error) {
|
||||||
return dao.GetStorageItemsWithPrefix(hash, nil)
|
return dao.GetStorageItemsWithPrefix(id, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageItemsWithPrefix returns all storage items with given prefix for a
|
// GetStorageItemsWithPrefix returns all storage items with given id for a
|
||||||
// given scripthash.
|
// given scripthash.
|
||||||
func (dao *Simple) GetStorageItemsWithPrefix(hash util.Uint160, prefix []byte) (map[string]*state.StorageItem, error) {
|
func (dao *Simple) GetStorageItemsWithPrefix(id int32, prefix []byte) (map[string]*state.StorageItem, error) {
|
||||||
var siMap = make(map[string]*state.StorageItem)
|
var siMap = make(map[string]*state.StorageItem)
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
lookupKey := storage.AppendPrefix(storage.STStorage, hash.BytesLE())
|
lookupKey := makeStorageItemKey(id, nil)
|
||||||
if prefix != nil {
|
if prefix != nil {
|
||||||
lookupKey = append(lookupKey, prefix...)
|
lookupKey = append(lookupKey, prefix...)
|
||||||
}
|
}
|
||||||
|
@ -362,8 +362,13 @@ func (dao *Simple) GetStorageItemsWithPrefix(hash util.Uint160, prefix []byte) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeStorageItemKey returns a key used to store StorageItem in the DB.
|
// makeStorageItemKey returns a key used to store StorageItem in the DB.
|
||||||
func makeStorageItemKey(scripthash util.Uint160, key []byte) []byte {
|
func makeStorageItemKey(id int32, key []byte) []byte {
|
||||||
return storage.AppendPrefix(storage.STStorage, append(scripthash.BytesLE(), key...))
|
// 1 for prefix + 4 for Uint32 + len(key) for key
|
||||||
|
buf := make([]byte, 5+len(key))
|
||||||
|
buf[0] = byte(storage.STStorage)
|
||||||
|
binary.LittleEndian.PutUint32(buf[1:], uint32(id))
|
||||||
|
copy(buf[5:], key)
|
||||||
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- end storage item.
|
// -- end storage item.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dao
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
@ -111,25 +112,25 @@ func TestPutGetAppExecResult(t *testing.T) {
|
||||||
|
|
||||||
func TestPutGetStorageItem(t *testing.T) {
|
func TestPutGetStorageItem(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet)
|
dao := NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet)
|
||||||
hash := random.Uint160()
|
id := int32(random.Int(0, 1024))
|
||||||
key := []byte{0}
|
key := []byte{0}
|
||||||
storageItem := &state.StorageItem{Value: []uint8{}}
|
storageItem := &state.StorageItem{Value: []uint8{}}
|
||||||
err := dao.PutStorageItem(hash, key, storageItem)
|
err := dao.PutStorageItem(id, key, storageItem)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
gotStorageItem := dao.GetStorageItem(hash, key)
|
gotStorageItem := dao.GetStorageItem(id, key)
|
||||||
require.Equal(t, storageItem, gotStorageItem)
|
require.Equal(t, storageItem, gotStorageItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteStorageItem(t *testing.T) {
|
func TestDeleteStorageItem(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet)
|
dao := NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet)
|
||||||
hash := random.Uint160()
|
id := int32(random.Int(0, 1024))
|
||||||
key := []byte{0}
|
key := []byte{0}
|
||||||
storageItem := &state.StorageItem{Value: []uint8{}}
|
storageItem := &state.StorageItem{Value: []uint8{}}
|
||||||
err := dao.PutStorageItem(hash, key, storageItem)
|
err := dao.PutStorageItem(id, key, storageItem)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = dao.DeleteStorageItem(hash, key)
|
err = dao.DeleteStorageItem(id, key)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
gotStorageItem := dao.GetStorageItem(hash, key)
|
gotStorageItem := dao.GetStorageItem(id, key)
|
||||||
require.Nil(t, gotStorageItem)
|
require.Nil(t, gotStorageItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,3 +209,16 @@ func TestStoreAsTransaction(t *testing.T) {
|
||||||
hasTransaction := dao.HasTransaction(hash)
|
hasTransaction := dao.HasTransaction(hash)
|
||||||
require.True(t, hasTransaction)
|
require.True(t, hasTransaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMakeStorageItemKey(t *testing.T) {
|
||||||
|
var id int32 = 5
|
||||||
|
|
||||||
|
expected := []byte{byte(storage.STStorage), 0, 0, 0, 0, 1, 2, 3}
|
||||||
|
binary.LittleEndian.PutUint32(expected[1:5], uint32(id))
|
||||||
|
actual := makeStorageItemKey(id, []byte{1, 2, 3})
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
|
||||||
|
expected = expected[0:5]
|
||||||
|
actual = makeStorageItemKey(id, nil)
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
|
@ -34,12 +34,8 @@ func storageFind(ic *interop.Context, v *vm.VM) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("%T is not a StorageContext", stcInterface)
|
return fmt.Errorf("%T is not a StorageContext", stcInterface)
|
||||||
}
|
}
|
||||||
err := checkStorageContext(ic, stc)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
prefix := v.Estack().Pop().Bytes()
|
prefix := v.Estack().Pop().Bytes()
|
||||||
siMap, err := ic.DAO.GetStorageItemsWithPrefix(stc.ScriptHash, prefix)
|
siMap, err := ic.DAO.GetStorageItemsWithPrefix(stc.ID, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -138,19 +134,13 @@ func contractUpdate(ic *interop.Context, v *vm.VM) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if contract.HasStorage() {
|
if !newcontract.HasStorage() {
|
||||||
// TODO store items by ID #1037
|
siMap, err := ic.DAO.GetStorageItems(contract.ID)
|
||||||
hash := v.GetCurrentScriptHash()
|
|
||||||
siMap, err := ic.DAO.GetStorageItems(hash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for k, v := range siMap {
|
if len(siMap) != 0 {
|
||||||
v.IsConst = false
|
return errors.New("old contract shouldn't have storage")
|
||||||
err = ic.DAO.PutStorageItem(contract.ScriptHash(), []byte(k), v)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.Estack().PushVal(stackitem.NewInterop(contract))
|
v.Estack().PushVal(stackitem.NewInterop(contract))
|
||||||
|
|
|
@ -63,16 +63,16 @@ func TestStorageFind(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, context.DAO.PutContractState(contractState))
|
require.NoError(t, context.DAO.PutContractState(contractState))
|
||||||
|
|
||||||
scriptHash := contractState.ScriptHash()
|
id := contractState.ID
|
||||||
|
|
||||||
for i := range skeys {
|
for i := range skeys {
|
||||||
err := context.DAO.PutStorageItem(scriptHash, skeys[i], items[i])
|
err := context.DAO.PutStorageItem(id, skeys[i], items[i])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("normal invocation", func(t *testing.T) {
|
t.Run("normal invocation", func(t *testing.T) {
|
||||||
v.Estack().PushVal([]byte{0x01})
|
v.Estack().PushVal([]byte{0x01})
|
||||||
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ScriptHash: scriptHash}))
|
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: id}))
|
||||||
|
|
||||||
err := storageFind(context, v)
|
err := storageFind(context, v)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -110,7 +110,7 @@ func TestStorageFind(t *testing.T) {
|
||||||
|
|
||||||
t.Run("normal invocation, empty result", func(t *testing.T) {
|
t.Run("normal invocation, empty result", func(t *testing.T) {
|
||||||
v.Estack().PushVal([]byte{0x03})
|
v.Estack().PushVal([]byte{0x03})
|
||||||
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ScriptHash: scriptHash}))
|
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: id}))
|
||||||
|
|
||||||
err := storageFind(context, v)
|
err := storageFind(context, v)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -126,14 +126,15 @@ func TestStorageFind(t *testing.T) {
|
||||||
require.Error(t, storageFind(context, v))
|
require.Error(t, storageFind(context, v))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("invalid script hash", func(t *testing.T) {
|
t.Run("invalid id", func(t *testing.T) {
|
||||||
invalidHash := scriptHash
|
invalidID := id + 1
|
||||||
invalidHash[0] = ^invalidHash[0]
|
|
||||||
|
|
||||||
v.Estack().PushVal([]byte{0x01})
|
v.Estack().PushVal([]byte{0x01})
|
||||||
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ScriptHash: invalidHash}))
|
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: invalidID}))
|
||||||
|
|
||||||
require.Error(t, storageFind(context, v))
|
require.NoError(t, storageFind(context, v))
|
||||||
|
require.NoError(t, enumerator.Next(context, v))
|
||||||
|
require.False(t, v.Estack().Pop().Bool())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +258,7 @@ func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.C
|
||||||
contractState := &state.Contract{
|
contractState := &state.Contract{
|
||||||
Script: script,
|
Script: script,
|
||||||
Manifest: *m,
|
Manifest: *m,
|
||||||
|
ID: 123,
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := newTestChain(t)
|
chain := newTestChain(t)
|
||||||
|
|
|
@ -28,11 +28,11 @@ const (
|
||||||
MaxTraceableBlocks = transaction.MaxValidUntilBlockIncrement
|
MaxTraceableBlocks = transaction.MaxValidUntilBlockIncrement
|
||||||
)
|
)
|
||||||
|
|
||||||
// StorageContext contains storing script hash and read/write flag, it's used as
|
// StorageContext contains storing id and read/write flag, it's used as
|
||||||
// a context for storage manipulation functions.
|
// a context for storage manipulation functions.
|
||||||
type StorageContext struct {
|
type StorageContext struct {
|
||||||
ScriptHash util.Uint160
|
ID int32
|
||||||
ReadOnly bool
|
ReadOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// getBlockHashFromElement converts given vm.Element to block hash using given
|
// getBlockHashFromElement converts given vm.Element to block hash using given
|
||||||
|
@ -259,17 +259,6 @@ func runtimeGetTime(ic *interop.Context, v *vm.VM) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkStorageContext(ic *interop.Context, stc *StorageContext) error {
|
|
||||||
contract, err := ic.DAO.GetContractState(stc.ScriptHash)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("no contract found")
|
|
||||||
}
|
|
||||||
if !contract.HasStorage() {
|
|
||||||
return fmt.Errorf("contract %s can't use storage", stc.ScriptHash)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// storageDelete deletes stored key-value pair.
|
// storageDelete deletes stored key-value pair.
|
||||||
func storageDelete(ic *interop.Context, v *vm.VM) error {
|
func storageDelete(ic *interop.Context, v *vm.VM) error {
|
||||||
stcInterface := v.Estack().Pop().Value()
|
stcInterface := v.Estack().Pop().Value()
|
||||||
|
@ -280,16 +269,12 @@ func storageDelete(ic *interop.Context, v *vm.VM) error {
|
||||||
if stc.ReadOnly {
|
if stc.ReadOnly {
|
||||||
return errors.New("StorageContext is read only")
|
return errors.New("StorageContext is read only")
|
||||||
}
|
}
|
||||||
err := checkStorageContext(ic, stc)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
key := v.Estack().Pop().Bytes()
|
key := v.Estack().Pop().Bytes()
|
||||||
si := ic.DAO.GetStorageItem(stc.ScriptHash, key)
|
si := ic.DAO.GetStorageItem(stc.ID, key)
|
||||||
if si != nil && si.IsConst {
|
if si != nil && si.IsConst {
|
||||||
return errors.New("storage item is constant")
|
return errors.New("storage item is constant")
|
||||||
}
|
}
|
||||||
return ic.DAO.DeleteStorageItem(stc.ScriptHash, key)
|
return ic.DAO.DeleteStorageItem(stc.ID, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// storageGet returns stored key-value pair.
|
// storageGet returns stored key-value pair.
|
||||||
|
@ -299,12 +284,8 @@ func storageGet(ic *interop.Context, v *vm.VM) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("%T is not a StorageContext", stcInterface)
|
return fmt.Errorf("%T is not a StorageContext", stcInterface)
|
||||||
}
|
}
|
||||||
err := checkStorageContext(ic, stc)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
key := v.Estack().Pop().Bytes()
|
key := v.Estack().Pop().Bytes()
|
||||||
si := ic.DAO.GetStorageItem(stc.ScriptHash, key)
|
si := ic.DAO.GetStorageItem(stc.ID, key)
|
||||||
if si != nil && si.Value != nil {
|
if si != nil && si.Value != nil {
|
||||||
v.Estack().PushVal(si.Value)
|
v.Estack().PushVal(si.Value)
|
||||||
} else {
|
} else {
|
||||||
|
@ -315,9 +296,16 @@ func storageGet(ic *interop.Context, v *vm.VM) error {
|
||||||
|
|
||||||
// storageGetContext returns storage context (scripthash).
|
// storageGetContext returns storage context (scripthash).
|
||||||
func storageGetContext(ic *interop.Context, v *vm.VM) error {
|
func storageGetContext(ic *interop.Context, v *vm.VM) error {
|
||||||
|
contract, err := ic.DAO.GetContractState(v.GetCurrentScriptHash())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !contract.HasStorage() {
|
||||||
|
return errors.New("contract is not allowed to use storage")
|
||||||
|
}
|
||||||
sc := &StorageContext{
|
sc := &StorageContext{
|
||||||
ScriptHash: v.GetCurrentScriptHash(),
|
ID: contract.ID,
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
}
|
}
|
||||||
v.Estack().PushVal(stackitem.NewInterop(sc))
|
v.Estack().PushVal(stackitem.NewInterop(sc))
|
||||||
return nil
|
return nil
|
||||||
|
@ -325,9 +313,16 @@ func storageGetContext(ic *interop.Context, v *vm.VM) error {
|
||||||
|
|
||||||
// storageGetReadOnlyContext returns read-only context (scripthash).
|
// storageGetReadOnlyContext returns read-only context (scripthash).
|
||||||
func storageGetReadOnlyContext(ic *interop.Context, v *vm.VM) error {
|
func storageGetReadOnlyContext(ic *interop.Context, v *vm.VM) error {
|
||||||
|
contract, err := ic.DAO.GetContractState(v.GetCurrentScriptHash())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !contract.HasStorage() {
|
||||||
|
return err
|
||||||
|
}
|
||||||
sc := &StorageContext{
|
sc := &StorageContext{
|
||||||
ScriptHash: v.GetCurrentScriptHash(),
|
ID: contract.ID,
|
||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
}
|
}
|
||||||
v.Estack().PushVal(stackitem.NewInterop(sc))
|
v.Estack().PushVal(stackitem.NewInterop(sc))
|
||||||
return nil
|
return nil
|
||||||
|
@ -340,11 +335,7 @@ func putWithContextAndFlags(ic *interop.Context, v *vm.VM, stc *StorageContext,
|
||||||
if stc.ReadOnly {
|
if stc.ReadOnly {
|
||||||
return errors.New("StorageContext is read only")
|
return errors.New("StorageContext is read only")
|
||||||
}
|
}
|
||||||
err := checkStorageContext(ic, stc)
|
si := ic.DAO.GetStorageItem(stc.ID, key)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
si := ic.DAO.GetStorageItem(stc.ScriptHash, key)
|
|
||||||
if si == nil {
|
if si == nil {
|
||||||
si = &state.StorageItem{}
|
si = &state.StorageItem{}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +351,7 @@ func putWithContextAndFlags(ic *interop.Context, v *vm.VM, stc *StorageContext,
|
||||||
}
|
}
|
||||||
si.Value = value
|
si.Value = value
|
||||||
si.IsConst = isConst
|
si.IsConst = isConst
|
||||||
return ic.DAO.PutStorageItem(stc.ScriptHash, key, si)
|
return ic.DAO.PutStorageItem(stc.ID, key, si)
|
||||||
}
|
}
|
||||||
|
|
||||||
// storagePutInternal is a unified implementation of storagePut and storagePutEx.
|
// storagePutInternal is a unified implementation of storagePut and storagePutEx.
|
||||||
|
@ -398,8 +389,8 @@ func storageContextAsReadOnly(ic *interop.Context, v *vm.VM) error {
|
||||||
}
|
}
|
||||||
if !stc.ReadOnly {
|
if !stc.ReadOnly {
|
||||||
stx := &StorageContext{
|
stx := &StorageContext{
|
||||||
ScriptHash: stc.ScriptHash,
|
ID: stc.ID,
|
||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
}
|
}
|
||||||
stc = stx
|
stc = stx
|
||||||
}
|
}
|
||||||
|
@ -462,12 +453,12 @@ func contractDestroy(ic *interop.Context, v *vm.VM) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cs.HasStorage() {
|
if cs.HasStorage() {
|
||||||
siMap, err := ic.DAO.GetStorageItems(hash)
|
siMap, err := ic.DAO.GetStorageItems(cs.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for k := range siMap {
|
for k := range siMap {
|
||||||
_ = ic.DAO.DeleteStorageItem(hash, []byte(k))
|
_ = ic.DAO.DeleteStorageItem(cs.ID, []byte(k))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -34,7 +34,7 @@ type keyWithVotes struct {
|
||||||
|
|
||||||
const (
|
const (
|
||||||
neoSyscallName = "Neo.Native.Tokens.NEO"
|
neoSyscallName = "Neo.Native.Tokens.NEO"
|
||||||
neoContractID = -2
|
neoContractID = -1
|
||||||
// NEOTotalSupply is the total amount of NEO in the system.
|
// NEOTotalSupply is the total amount of NEO in the system.
|
||||||
NEOTotalSupply = 100000000
|
NEOTotalSupply = 100000000
|
||||||
// prefixValidator is a prefix used to store validator's data.
|
// prefixValidator is a prefix used to store validator's data.
|
||||||
|
@ -124,7 +124,7 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
||||||
|
|
||||||
vc := new(ValidatorsCount)
|
vc := new(ValidatorsCount)
|
||||||
si.Value = vc.Bytes()
|
si.Value = vc.Bytes()
|
||||||
if err := ic.DAO.PutStorageItem(n.Hash, validatorsCountKey, &si); err != nil {
|
if err := ic.DAO.PutStorageItem(n.ContractID, validatorsCountKey, &si); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
h, vs, err := getStandbyValidatorsHash(ic)
|
h, vs, err := getStandbyValidatorsHash(ic)
|
||||||
|
@ -150,7 +150,7 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
|
||||||
}
|
}
|
||||||
si := new(state.StorageItem)
|
si := new(state.StorageItem)
|
||||||
si.Value = pubs.Bytes()
|
si.Value = pubs.Bytes()
|
||||||
return ic.DAO.PutStorageItem(n.Hash, nextValidatorsKey, si)
|
return ic.DAO.PutStorageItem(n.ContractID, nextValidatorsKey, si)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.StorageItem, amount *big.Int) error {
|
func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.StorageItem, amount *big.Int) error {
|
||||||
|
@ -171,7 +171,7 @@ func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.Sto
|
||||||
if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance)); err != nil {
|
if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
siVC := ic.DAO.GetStorageItem(n.Hash, validatorsCountKey)
|
siVC := ic.DAO.GetStorageItem(n.ContractID, validatorsCountKey)
|
||||||
if siVC == nil {
|
if siVC == nil {
|
||||||
return errors.New("validators count uninitialized")
|
return errors.New("validators count uninitialized")
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.Sto
|
||||||
}
|
}
|
||||||
vc[len(acc.Votes)-1].Add(&vc[len(acc.Votes)-1], amount)
|
vc[len(acc.Votes)-1].Add(&vc[len(acc.Votes)-1], amount)
|
||||||
siVC.Value = vc.Bytes()
|
siVC.Value = vc.Bytes()
|
||||||
if err := ic.DAO.PutStorageItem(n.Hash, validatorsCountKey, siVC); err != nil {
|
if err := ic.DAO.PutStorageItem(n.ContractID, validatorsCountKey, siVC); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ func (n *NEO) registerValidator(ic *interop.Context, args []stackitem.Item) stac
|
||||||
|
|
||||||
func (n *NEO) registerValidatorInternal(ic *interop.Context, pub *keys.PublicKey) error {
|
func (n *NEO) registerValidatorInternal(ic *interop.Context, pub *keys.PublicKey) error {
|
||||||
key := makeValidatorKey(pub)
|
key := makeValidatorKey(pub)
|
||||||
si := ic.DAO.GetStorageItem(n.Hash, key)
|
si := ic.DAO.GetStorageItem(n.ContractID, key)
|
||||||
if si != nil {
|
if si != nil {
|
||||||
return errors.New("already registered")
|
return errors.New("already registered")
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ func (n *NEO) registerValidatorInternal(ic *interop.Context, pub *keys.PublicKey
|
||||||
// doesn't help a lot.
|
// doesn't help a lot.
|
||||||
votes := state.NEP5BalanceState{}
|
votes := state.NEP5BalanceState{}
|
||||||
si.Value = votes.Bytes()
|
si.Value = votes.Bytes()
|
||||||
return ic.DAO.PutStorageItem(n.Hash, key, si)
|
return ic.DAO.PutStorageItem(n.ContractID, key, si)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||||
|
@ -263,7 +263,7 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
|
||||||
return errors.New("invalid signature")
|
return errors.New("invalid signature")
|
||||||
}
|
}
|
||||||
key := makeAccountKey(h)
|
key := makeAccountKey(h)
|
||||||
si := ic.DAO.GetStorageItem(n.Hash, key)
|
si := ic.DAO.GetStorageItem(n.ContractID, key)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
return errors.New("invalid account")
|
return errors.New("invalid account")
|
||||||
}
|
}
|
||||||
|
@ -278,13 +278,13 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
|
||||||
// Check validators registration.
|
// Check validators registration.
|
||||||
var newPubs keys.PublicKeys
|
var newPubs keys.PublicKeys
|
||||||
for _, pub := range pubs {
|
for _, pub := range pubs {
|
||||||
if ic.DAO.GetStorageItem(n.Hash, makeValidatorKey(pub)) == nil {
|
if ic.DAO.GetStorageItem(n.ContractID, makeValidatorKey(pub)) == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newPubs = append(newPubs, pub)
|
newPubs = append(newPubs, pub)
|
||||||
}
|
}
|
||||||
if lp, lv := len(newPubs), len(acc.Votes); lp != lv {
|
if lp, lv := len(newPubs), len(acc.Votes); lp != lv {
|
||||||
si := ic.DAO.GetStorageItem(n.Hash, validatorsCountKey)
|
si := ic.DAO.GetStorageItem(n.ContractID, validatorsCountKey)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
return errors.New("validators count uninitialized")
|
return errors.New("validators count uninitialized")
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
|
||||||
vc[lp-1].Add(&vc[lp-1], &acc.Balance)
|
vc[lp-1].Add(&vc[lp-1], &acc.Balance)
|
||||||
}
|
}
|
||||||
si.Value = vc.Bytes()
|
si.Value = vc.Bytes()
|
||||||
if err := ic.DAO.PutStorageItem(n.Hash, validatorsCountKey, si); err != nil {
|
if err := ic.DAO.PutStorageItem(n.ContractID, validatorsCountKey, si); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,14 +308,14 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
si.Value = acc.Bytes()
|
si.Value = acc.Bytes()
|
||||||
return ic.DAO.PutStorageItem(n.Hash, key, si)
|
return ic.DAO.PutStorageItem(n.ContractID, key, si)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModifyAccountVotes modifies votes of the specified account by value (can be negative).
|
// ModifyAccountVotes modifies votes of the specified account by value (can be negative).
|
||||||
func (n *NEO) ModifyAccountVotes(acc *state.NEOBalanceState, d dao.DAO, value *big.Int) error {
|
func (n *NEO) ModifyAccountVotes(acc *state.NEOBalanceState, d dao.DAO, value *big.Int) error {
|
||||||
for _, vote := range acc.Votes {
|
for _, vote := range acc.Votes {
|
||||||
key := makeValidatorKey(vote)
|
key := makeValidatorKey(vote)
|
||||||
si := d.GetStorageItem(n.Hash, key)
|
si := d.GetStorageItem(n.ContractID, key)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
return errors.New("invalid validator")
|
return errors.New("invalid validator")
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ func (n *NEO) ModifyAccountVotes(acc *state.NEOBalanceState, d dao.DAO, value *b
|
||||||
}
|
}
|
||||||
votes.Balance.Add(&votes.Balance, value)
|
votes.Balance.Add(&votes.Balance, value)
|
||||||
si.Value = votes.Bytes()
|
si.Value = votes.Bytes()
|
||||||
if err := d.PutStorageItem(n.Hash, key, si); err != nil {
|
if err := d.PutStorageItem(n.ContractID, key, si); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ func (n *NEO) ModifyAccountVotes(acc *state.NEOBalanceState, d dao.DAO, value *b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NEO) getRegisteredValidators(d dao.DAO) ([]keyWithVotes, error) {
|
func (n *NEO) getRegisteredValidators(d dao.DAO) ([]keyWithVotes, error) {
|
||||||
siMap, err := d.GetStorageItemsWithPrefix(n.Hash, []byte{prefixValidator})
|
siMap, err := d.GetStorageItemsWithPrefix(n.ContractID, []byte{prefixValidator})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -384,7 +384,7 @@ func (n *NEO) getRegisteredValidatorsCall(ic *interop.Context, _ []stackitem.Ite
|
||||||
|
|
||||||
// GetValidatorsInternal returns a list of current validators.
|
// GetValidatorsInternal returns a list of current validators.
|
||||||
func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
|
func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
|
||||||
si := d.GetStorageItem(n.Hash, validatorsCountKey)
|
si := d.GetStorageItem(n.ContractID, validatorsCountKey)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
return nil, errors.New("validators count uninitialized")
|
return nil, errors.New("validators count uninitialized")
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@ func (n *NEO) getNextBlockValidators(ic *interop.Context, _ []stackitem.Item) st
|
||||||
|
|
||||||
// GetNextBlockValidatorsInternal returns next block validators.
|
// GetNextBlockValidatorsInternal returns next block validators.
|
||||||
func (n *NEO) GetNextBlockValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
|
func (n *NEO) GetNextBlockValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
|
||||||
si := d.GetStorageItem(n.Hash, nextValidatorsKey)
|
si := d.GetStorageItem(n.ContractID, nextValidatorsKey)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
return n.GetValidatorsInternal(bc, d)
|
return n.GetValidatorsInternal(bc, d)
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ func (c *nep5TokenNative) TotalSupply(ic *interop.Context, _ []stackitem.Item) s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *nep5TokenNative) getTotalSupply(ic *interop.Context) *big.Int {
|
func (c *nep5TokenNative) getTotalSupply(ic *interop.Context) *big.Int {
|
||||||
si := ic.DAO.GetStorageItem(c.Hash, totalSupplyKey)
|
si := ic.DAO.GetStorageItem(c.ContractID, totalSupplyKey)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
return big.NewInt(0)
|
return big.NewInt(0)
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ func (c *nep5TokenNative) getTotalSupply(ic *interop.Context) *big.Int {
|
||||||
|
|
||||||
func (c *nep5TokenNative) saveTotalSupply(ic *interop.Context, supply *big.Int) error {
|
func (c *nep5TokenNative) saveTotalSupply(ic *interop.Context, supply *big.Int) error {
|
||||||
si := &state.StorageItem{Value: bigint.ToBytes(supply)}
|
si := &state.StorageItem{Value: bigint.ToBytes(supply)}
|
||||||
return ic.DAO.PutStorageItem(c.Hash, totalSupplyKey, si)
|
return ic.DAO.PutStorageItem(c.ContractID, totalSupplyKey, si)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *nep5TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
func (c *nep5TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||||
|
@ -165,7 +165,7 @@ func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, a
|
||||||
}
|
}
|
||||||
|
|
||||||
keyFrom := makeAccountKey(from)
|
keyFrom := makeAccountKey(from)
|
||||||
siFrom := ic.DAO.GetStorageItem(c.Hash, keyFrom)
|
siFrom := ic.DAO.GetStorageItem(c.ContractID, keyFrom)
|
||||||
if siFrom == nil {
|
if siFrom == nil {
|
||||||
return errors.New("insufficient funds")
|
return errors.New("insufficient funds")
|
||||||
}
|
}
|
||||||
|
@ -180,20 +180,20 @@ func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, a
|
||||||
if err := c.incBalance(ic, from, siFrom, inc); err != nil {
|
if err := c.incBalance(ic, from, siFrom, inc); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ic.DAO.PutStorageItem(c.Hash, keyFrom, siFrom); err != nil {
|
if err := ic.DAO.PutStorageItem(c.ContractID, keyFrom, siFrom); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isEmpty {
|
if !isEmpty {
|
||||||
keyTo := makeAccountKey(to)
|
keyTo := makeAccountKey(to)
|
||||||
siTo := ic.DAO.GetStorageItem(c.Hash, keyTo)
|
siTo := ic.DAO.GetStorageItem(c.ContractID, keyTo)
|
||||||
if siTo == nil {
|
if siTo == nil {
|
||||||
siTo = new(state.StorageItem)
|
siTo = new(state.StorageItem)
|
||||||
}
|
}
|
||||||
if err := c.incBalance(ic, to, siTo, amount); err != nil {
|
if err := c.incBalance(ic, to, siTo, amount); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ic.DAO.PutStorageItem(c.Hash, keyTo, siTo); err != nil {
|
if err := ic.DAO.PutStorageItem(c.ContractID, keyTo, siTo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,14 +234,14 @@ func (c *nep5TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount
|
||||||
}
|
}
|
||||||
|
|
||||||
key := makeAccountKey(h)
|
key := makeAccountKey(h)
|
||||||
si := ic.DAO.GetStorageItem(c.Hash, key)
|
si := ic.DAO.GetStorageItem(c.ContractID, key)
|
||||||
if si == nil {
|
if si == nil {
|
||||||
si = new(state.StorageItem)
|
si = new(state.StorageItem)
|
||||||
}
|
}
|
||||||
if err := c.incBalance(ic, h, si, amount); err != nil {
|
if err := c.incBalance(ic, h, si, amount); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := ic.DAO.PutStorageItem(c.Hash, key, si); err != nil {
|
if err := ic.DAO.PutStorageItem(c.ContractID, key, si); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,13 +94,13 @@ func (chain testChain) GetEnrollments() ([]state.Validator, error) {
|
||||||
func (chain testChain) GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error) {
|
func (chain testChain) GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
func (chain testChain) GetStorageItem(id int32, key []byte) *state.StorageItem {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetTestVM(tx *transaction.Transaction) *vm.VM {
|
func (chain testChain) GetTestVM(tx *transaction.Transaction) *vm.VM {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error) {
|
func (chain testChain) GetStorageItems(id int32) (map[string]*state.StorageItem, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) CurrentHeaderHash() util.Uint256 {
|
func (chain testChain) CurrentHeaderHash() util.Uint256 {
|
||||||
|
|
|
@ -634,18 +634,44 @@ func (s *Server) getDecimals(h util.Uint160, cache map[util.Uint160]int64) (int6
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Error) {
|
||||||
|
var result int32
|
||||||
|
switch param.Type {
|
||||||
|
case request.StringT:
|
||||||
|
var err error
|
||||||
|
scriptHash, err := param.GetUint160FromHex()
|
||||||
|
if err != nil {
|
||||||
|
return 0, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
cs := s.chain.GetContractState(scriptHash)
|
||||||
|
if cs == nil {
|
||||||
|
return 0, response.ErrUnknown
|
||||||
|
}
|
||||||
|
result = cs.ID
|
||||||
|
case request.NumberT:
|
||||||
|
id, err := param.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return 0, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
result = int32(id)
|
||||||
|
default:
|
||||||
|
return 0, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) {
|
func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) {
|
||||||
param, ok := ps.Value(0)
|
param, ok := ps.Value(0)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
id, rErr := s.contractIDFromParam(param)
|
||||||
scriptHash, err := param.GetUint160FromHex()
|
if rErr == response.ErrUnknown {
|
||||||
if err != nil {
|
return nil, nil
|
||||||
return nil, response.ErrInvalidParams
|
}
|
||||||
|
if rErr != nil {
|
||||||
|
return nil, rErr
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptHash = scriptHash.Reverse()
|
|
||||||
|
|
||||||
param, ok = ps.Value(1)
|
param, ok = ps.Value(1)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -657,7 +683,7 @@ func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
|
||||||
item := s.chain.GetStorageItem(scriptHash.Reverse(), key)
|
item := s.chain.GetStorageItem(id, key)
|
||||||
if item == nil {
|
if item == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue