Merge pull request #1013 from nspcc-dev/neo3/vm/stackitem_refactoring

vm: move StackItem to a separate package
This commit is contained in:
Roman Khimov 2020-06-08 15:30:44 +03:00 committed by GitHub
commit 795523f5cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 2575 additions and 2466 deletions

View file

@ -18,11 +18,13 @@ 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/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"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"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/pkg/errors"
"go.uber.org/zap"
)
@ -573,7 +575,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
return errors.Wrap(err, "failed to persist invocation results")
}
for _, note := range systemInterop.Notifications {
arr, ok := note.Item.Value().([]vm.StackItem)
arr, ok := note.Item.Value().([]stackitem.Item)
if !ok || len(arr) != 4 {
continue
}
@ -605,7 +607,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
if !ok {
continue
}
amount = emit.BytesToInt(bs)
amount = bigint.FromBytes(bs)
}
bc.processNEP5Transfer(cache, tx, block, note.ScriptHash, from, to, amount.Int64())
}

View file

@ -15,6 +15,7 @@ import (
"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"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"go.uber.org/zap"
)
@ -60,7 +61,7 @@ type Function struct {
}
// Method is a signature for a native method.
type Method = func(ic *Context, args []vm.StackItem) vm.StackItem
type Method = func(ic *Context, args []stackitem.Item) stackitem.Item
// MethodAndPrice is a native-contract method descriptor.
type MethodAndPrice struct {

View file

@ -9,6 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// ECDSAVerify checks ECDSA signature.
@ -48,12 +49,12 @@ func ECDSACheckMultisig(ic *interop.Context, v *vm.VM) error {
return nil
}
func getMessage(ic *interop.Context, item vm.StackItem) []byte {
func getMessage(ic *interop.Context, item stackitem.Item) []byte {
var msg []byte
switch val := item.(type) {
case *vm.InteropItem:
case *stackitem.Interop:
msg = val.Value().(crypto.Verifiable).GetSignedPart()
case vm.NullItem:
case stackitem.Null:
msg = ic.Container.GetSignedPart()
default:
var err error

View file

@ -9,16 +9,17 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func initCHECKMULTISIG(msg []byte, n int) ([]vm.StackItem, []vm.StackItem, map[string]*keys.PublicKey, error) {
func initCHECKMULTISIG(msg []byte, n int) ([]stackitem.Item, []stackitem.Item, map[string]*keys.PublicKey, error) {
var err error
keyMap := make(map[string]*keys.PublicKey)
pkeys := make([]*keys.PrivateKey, n)
pubs := make([]vm.StackItem, n)
pubs := make([]stackitem.Item, n)
for i := range pubs {
pkeys[i], err = keys.NewPrivateKey()
if err != nil {
@ -27,25 +28,25 @@ func initCHECKMULTISIG(msg []byte, n int) ([]vm.StackItem, []vm.StackItem, map[s
pk := pkeys[i].PublicKey()
data := pk.Bytes()
pubs[i] = vm.NewByteArrayItem(data)
pubs[i] = stackitem.NewByteArray(data)
keyMap[string(data)] = pk
}
sigs := make([]vm.StackItem, n)
sigs := make([]stackitem.Item, n)
for i := range sigs {
sig := pkeys[i].Sign(msg)
sigs[i] = vm.NewByteArrayItem(sig)
sigs[i] = stackitem.NewByteArray(sig)
}
return pubs, sigs, keyMap, nil
}
func subSlice(arr []vm.StackItem, indices []int) []vm.StackItem {
func subSlice(arr []stackitem.Item, indices []int) []stackitem.Item {
if indices == nil {
return arr
}
result := make([]vm.StackItem, len(indices))
result := make([]stackitem.Item, len(indices))
for i, j := range indices {
result[i] = arr[j]
}

View file

@ -13,6 +13,7 @@ import (
"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/stackitem"
)
const (
@ -66,9 +67,9 @@ func txGetAttributes(ic *interop.Context, v *vm.VM) error {
if len(tx.Attributes) > vm.MaxArraySize {
return errors.New("too many attributes")
}
attrs := make([]vm.StackItem, 0, len(tx.Attributes))
attrs := make([]stackitem.Item, 0, len(tx.Attributes))
for i := range tx.Attributes {
attrs = append(attrs, vm.NewInteropItem(&tx.Attributes[i]))
attrs = append(attrs, stackitem.NewInterop(&tx.Attributes[i]))
}
v.Estack().PushVal(attrs)
return nil
@ -84,9 +85,9 @@ func txGetWitnesses(ic *interop.Context, v *vm.VM) error {
if len(tx.Scripts) > vm.MaxArraySize {
return errors.New("too many outputs")
}
scripts := make([]vm.StackItem, 0, len(tx.Scripts))
scripts := make([]stackitem.Item, 0, len(tx.Scripts))
for i := range tx.Scripts {
scripts = append(scripts, vm.NewInteropItem(&tx.Scripts[i]))
scripts = append(scripts, stackitem.NewInterop(&tx.Scripts[i]))
}
v.Estack().PushVal(scripts)
return nil
@ -139,7 +140,7 @@ func bcGetAccount(ic *interop.Context, v *vm.VM) error {
if err != nil {
return err
}
v.Estack().PushVal(vm.NewInteropItem(acc))
v.Estack().PushVal(stackitem.NewInterop(acc))
return nil
}
@ -204,13 +205,13 @@ func storageFind(ic *interop.Context, v *vm.VM) error {
return err
}
filteredMap := vm.NewMapItem()
filteredMap := stackitem.NewMap()
for k, v := range siMap {
filteredMap.Add(vm.NewByteArrayItem(append(prefix, []byte(k)...)), vm.NewByteArrayItem(v.Value))
filteredMap.Add(stackitem.NewByteArray(append(prefix, []byte(k)...)), stackitem.NewByteArray(v.Value))
}
sort.Slice(filteredMap.Value().([]vm.MapElement), func(i, j int) bool {
return bytes.Compare(filteredMap.Value().([]vm.MapElement)[i].Key.Value().([]byte),
filteredMap.Value().([]vm.MapElement)[j].Key.Value().([]byte)) == -1
sort.Slice(filteredMap.Value().([]stackitem.MapElement), func(i, j int) bool {
return bytes.Compare(filteredMap.Value().([]stackitem.MapElement)[i].Key.Value().([]byte),
filteredMap.Value().([]stackitem.MapElement)[j].Key.Value().([]byte)) == -1
})
item := vm.NewMapIterator(filteredMap)
@ -288,7 +289,7 @@ func contractCreate(ic *interop.Context, v *vm.VM) error {
return err
}
}
v.Estack().PushVal(vm.NewInteropItem(contract))
v.Estack().PushVal(stackitem.NewInterop(contract))
return nil
}
@ -342,7 +343,7 @@ func contractMigrate(ic *interop.Context, v *vm.VM) error {
}
}
}
v.Estack().PushVal(vm.NewInteropItem(contract))
v.Estack().PushVal(stackitem.NewInterop(contract))
return contractDestroy(ic, v)
}

View file

@ -21,6 +21,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
@ -70,12 +71,12 @@ func TestStorageFind(t *testing.T) {
t.Run("normal invocation", func(t *testing.T) {
v.Estack().PushVal([]byte{0x01})
v.Estack().PushVal(vm.NewInteropItem(&StorageContext{ScriptHash: scriptHash}))
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ScriptHash: scriptHash}))
err := storageFind(context, v)
require.NoError(t, err)
var iter *vm.InteropItem
var iter *stackitem.Interop
require.NotPanics(t, func() { iter = v.Estack().Top().Interop() })
require.NoError(t, enumerator.Next(context, v))
@ -108,7 +109,7 @@ func TestStorageFind(t *testing.T) {
t.Run("normal invocation, empty result", func(t *testing.T) {
v.Estack().PushVal([]byte{0x03})
v.Estack().PushVal(vm.NewInteropItem(&StorageContext{ScriptHash: scriptHash}))
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ScriptHash: scriptHash}))
err := storageFind(context, v)
require.NoError(t, err)
@ -119,7 +120,7 @@ func TestStorageFind(t *testing.T) {
t.Run("invalid type for StorageContext", func(t *testing.T) {
v.Estack().PushVal([]byte{0x01})
v.Estack().PushVal(vm.NewInteropItem(nil))
v.Estack().PushVal(stackitem.NewInterop(nil))
require.Error(t, storageFind(context, v))
})
@ -129,7 +130,7 @@ func TestStorageFind(t *testing.T) {
invalidHash[0] = ^invalidHash[0]
v.Estack().PushVal([]byte{0x01})
v.Estack().PushVal(vm.NewInteropItem(&StorageContext{ScriptHash: invalidHash}))
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ScriptHash: invalidHash}))
require.Error(t, storageFind(context, v))
})
@ -151,7 +152,7 @@ func TestHeaderGetVersion_Negative(t *testing.T) {
chain := newTestChain(t)
defer chain.Close()
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), block, nil)
v.Estack().PushVal(vm.NewBoolItem(false))
v.Estack().PushVal(stackitem.NewBool(false))
err := headerGetVersion(context, v)
require.Errorf(t, err, "value is not a header or block")
@ -183,7 +184,7 @@ func TestTxGetAttributes(t *testing.T) {
err := txGetAttributes(context, v)
require.NoError(t, err)
value := v.Estack().Pop().Value().([]vm.StackItem)
value := v.Estack().Pop().Value().([]stackitem.Item)
require.Equal(t, tx.Attributes[0].Usage, value[0].Value().(*transaction.Attribute).Usage)
}
@ -196,7 +197,7 @@ func TestWitnessGetVerificationScript(t *testing.T) {
defer chain.Close()
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), nil, nil)
v.Estack().PushVal(vm.NewInteropItem(&witness))
v.Estack().PushVal(stackitem.NewInterop(&witness))
err := witnessGetVerificationScript(context, v)
require.NoError(t, err)
value := v.Estack().Pop().Value().([]byte)
@ -247,7 +248,7 @@ func TestECDSAVerify(t *testing.T) {
tx := transaction.New([]byte{0, 1, 2}, 1)
msg := tx.GetSignedPart()
sign := priv.Sign(msg)
runCase(t, false, true, sign, priv.PublicKey().Bytes(), vm.NewInteropItem(tx))
runCase(t, false, true, sign, priv.PublicKey().Bytes(), stackitem.NewInterop(tx))
})
t.Run("signed script container", func(t *testing.T) {
@ -255,7 +256,7 @@ func TestECDSAVerify(t *testing.T) {
msg := tx.GetSignedPart()
sign := priv.Sign(msg)
ic.Container = tx
runCase(t, false, true, sign, priv.PublicKey().Bytes(), vm.NullItem{})
runCase(t, false, true, sign, priv.PublicKey().Bytes(), stackitem.Null{})
})
t.Run("missing arguments", func(t *testing.T) {
@ -282,7 +283,7 @@ func TestECDSAVerify(t *testing.T) {
func TestAttrGetData(t *testing.T) {
v, tx, context, chain := createVMAndTX(t)
defer chain.Close()
v.Estack().PushVal(vm.NewInteropItem(&tx.Attributes[0]))
v.Estack().PushVal(stackitem.NewInterop(&tx.Attributes[0]))
err := attrGetData(context, v)
require.NoError(t, err)
@ -293,7 +294,7 @@ func TestAttrGetData(t *testing.T) {
func TestAttrGetUsage(t *testing.T) {
v, tx, context, chain := createVMAndTX(t)
defer chain.Close()
v.Estack().PushVal(vm.NewInteropItem(&tx.Attributes[0]))
v.Estack().PushVal(stackitem.NewInterop(&tx.Attributes[0]))
err := attrGetUsage(context, v)
require.NoError(t, err)
@ -304,7 +305,7 @@ func TestAttrGetUsage(t *testing.T) {
func TestAccountGetScriptHash(t *testing.T) {
v, accState, context, chain := createVMAndAccState(t)
defer chain.Close()
v.Estack().PushVal(vm.NewInteropItem(accState))
v.Estack().PushVal(stackitem.NewInterop(accState))
err := accountGetScriptHash(context, v)
require.NoError(t, err)
@ -315,7 +316,7 @@ func TestAccountGetScriptHash(t *testing.T) {
func TestContractGetScript(t *testing.T) {
v, contractState, context, chain := createVMAndContractState(t)
defer chain.Close()
v.Estack().PushVal(vm.NewInteropItem(contractState))
v.Estack().PushVal(stackitem.NewInterop(contractState))
err := contractGetScript(context, v)
require.NoError(t, err)
@ -326,7 +327,7 @@ func TestContractGetScript(t *testing.T) {
func TestContractIsPayable(t *testing.T) {
v, contractState, context, chain := createVMAndContractState(t)
defer chain.Close()
v.Estack().PushVal(vm.NewInteropItem(contractState))
v.Estack().PushVal(stackitem.NewInterop(contractState))
err := contractIsPayable(context, v)
require.NoError(t, err)
@ -341,13 +342,13 @@ func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context,
block := newDumbBlock()
chain := newTestChain(t)
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), block, nil)
v.Estack().PushVal(vm.NewInteropItem(block))
v.Estack().PushVal(stackitem.NewInterop(block))
return v, block, context, chain
}
func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop.Context, *Blockchain) {
v, tx, context, chain := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(tx))
v.Estack().PushVal(stackitem.NewInterop(tx))
return v, tx, context, chain
}

View file

@ -15,6 +15,7 @@ import (
"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/stackitem"
"go.uber.org/zap"
)
@ -58,7 +59,7 @@ func bcGetBlock(ic *interop.Context, v *vm.VM) error {
if err != nil {
v.Estack().PushVal([]byte{})
} else {
v.Estack().PushVal(vm.NewInteropItem(block))
v.Estack().PushVal(stackitem.NewInterop(block))
}
return nil
}
@ -74,7 +75,7 @@ func bcGetContract(ic *interop.Context, v *vm.VM) error {
if err != nil {
v.Estack().PushVal([]byte{})
} else {
v.Estack().PushVal(vm.NewInteropItem(cs))
v.Estack().PushVal(stackitem.NewInterop(cs))
}
return nil
}
@ -89,7 +90,7 @@ func bcGetHeader(ic *interop.Context, v *vm.VM) error {
if err != nil {
v.Estack().PushVal([]byte{})
} else {
v.Estack().PushVal(vm.NewInteropItem(header))
v.Estack().PushVal(stackitem.NewInterop(header))
}
return nil
}
@ -117,7 +118,7 @@ func bcGetTransaction(ic *interop.Context, v *vm.VM) error {
if err != nil {
return err
}
v.Estack().PushVal(vm.NewInteropItem(tx))
v.Estack().PushVal(stackitem.NewInterop(tx))
return nil
}
@ -208,9 +209,9 @@ func blockGetTransactions(ic *interop.Context, v *vm.VM) error {
if len(block.Transactions) > vm.MaxArraySize {
return errors.New("too many transactions")
}
txes := make([]vm.StackItem, 0, len(block.Transactions))
txes := make([]stackitem.Item, 0, len(block.Transactions))
for _, tx := range block.Transactions {
txes = append(txes, vm.NewInteropItem(tx))
txes = append(txes, stackitem.NewInterop(tx))
}
v.Estack().PushVal(txes)
return nil
@ -229,7 +230,7 @@ func blockGetTransaction(ic *interop.Context, v *vm.VM) error {
return errors.New("wrong transaction index")
}
tx := block.Transactions[index]
v.Estack().PushVal(vm.NewInteropItem(tx))
v.Estack().PushVal(stackitem.NewInterop(tx))
return nil
}
@ -247,7 +248,7 @@ func txGetHash(ic *interop.Context, v *vm.VM) error {
// engineGetScriptContainer returns transaction that contains the script being
// run.
func engineGetScriptContainer(ic *interop.Context, v *vm.VM) error {
v.Estack().PushVal(vm.NewInteropItem(ic.Container))
v.Estack().PushVal(stackitem.NewInterop(ic.Container))
return nil
}
@ -289,9 +290,9 @@ func runtimeNotify(ic *interop.Context, v *vm.VM) error {
// outside of the interop subsystem anyway. I'd probably fail transactions
// that emit such broken notifications, but that might break compatibility
// with testnet/mainnet, so we're replacing these with error messages.
_, err := vm.SerializeItem(item)
_, err := stackitem.SerializeItem(item)
if err != nil {
item = vm.NewByteArrayItem([]byte(fmt.Sprintf("bad notification: %v", err)))
item = stackitem.NewByteArray([]byte(fmt.Sprintf("bad notification: %v", err)))
}
ne := state.NotificationEvent{ScriptHash: v.GetCurrentScriptHash(), Item: item}
ic.Notifications = append(ic.Notifications, ne)
@ -387,7 +388,7 @@ func storageGetContext(ic *interop.Context, v *vm.VM) error {
ScriptHash: v.GetCurrentScriptHash(),
ReadOnly: false,
}
v.Estack().PushVal(vm.NewInteropItem(sc))
v.Estack().PushVal(stackitem.NewInterop(sc))
return nil
}
@ -397,7 +398,7 @@ func storageGetReadOnlyContext(ic *interop.Context, v *vm.VM) error {
ScriptHash: v.GetCurrentScriptHash(),
ReadOnly: true,
}
v.Estack().PushVal(vm.NewInteropItem(sc))
v.Estack().PushVal(stackitem.NewInterop(sc))
return nil
}
@ -467,7 +468,7 @@ func storageContextAsReadOnly(ic *interop.Context, v *vm.VM) error {
}
stc = stx
}
v.Estack().PushVal(vm.NewInteropItem(stc))
v.Estack().PushVal(stackitem.NewInterop(stc))
return nil
}
@ -488,7 +489,7 @@ func contractCallEx(ic *interop.Context, v *vm.VM) error {
return contractCallExInternal(ic, v, h, method, args, flags)
}
func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method vm.StackItem, args vm.StackItem, _ smartcontract.CallFlag) error {
func contractCallExInternal(ic *interop.Context, v *vm.VM, h []byte, method stackitem.Item, args stackitem.Item, _ smartcontract.CallFlag) error {
u, err := util.Uint160DecodeBytesBE(h)
if err != nil {
return errors.New("invalid contract hash")
@ -548,6 +549,6 @@ func contractGetStorageContext(ic *interop.Context, v *vm.VM) error {
stc := &StorageContext{
ScriptHash: cs.ScriptHash(),
}
v.Estack().PushVal(vm.NewInteropItem(stc))
v.Estack().PushVal(stackitem.NewInterop(stc))
return nil
}

View file

@ -14,7 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/pkg/errors"
)
@ -194,7 +194,7 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
return nil
}
func (n *NEO) unclaimedGas(ic *interop.Context, args []vm.StackItem) vm.StackItem {
func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem.Item {
u := toUint160(args[0])
end := uint32(toBigInt(args[1]).Int64())
bs, err := ic.DAO.GetNEP5Balances(u)
@ -204,12 +204,12 @@ func (n *NEO) unclaimedGas(ic *interop.Context, args []vm.StackItem) vm.StackIte
tr := bs.Trackers[n.Hash]
gen := ic.Chain.CalculateClaimable(tr.Balance, tr.LastUpdatedBlock, end)
return vm.NewBigIntegerItem(big.NewInt(int64(gen)))
return stackitem.NewBigInteger(big.NewInt(int64(gen)))
}
func (n *NEO) registerValidator(ic *interop.Context, args []vm.StackItem) vm.StackItem {
func (n *NEO) registerValidator(ic *interop.Context, args []stackitem.Item) stackitem.Item {
err := n.registerValidatorInternal(ic, toPublicKey(args[0]))
return vm.NewBoolItem(err == nil)
return stackitem.NewBool(err == nil)
}
func (n *NEO) registerValidatorInternal(ic *interop.Context, pub *keys.PublicKey) error {
@ -226,9 +226,9 @@ func (n *NEO) registerValidatorInternal(ic *interop.Context, pub *keys.PublicKey
return ic.DAO.PutStorageItem(n.Hash, key, si)
}
func (n *NEO) vote(ic *interop.Context, args []vm.StackItem) vm.StackItem {
func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
acc := toUint160(args[0])
arr := args[1].Value().([]vm.StackItem)
arr := args[1].Value().([]stackitem.Item)
var pubs keys.PublicKeys
for i := range arr {
pub := new(keys.PublicKey)
@ -241,7 +241,7 @@ func (n *NEO) vote(ic *interop.Context, args []vm.StackItem) vm.StackItem {
pubs = append(pubs, pub)
}
err := n.VoteInternal(ic, acc, pubs)
return vm.NewBoolItem(err == nil)
return stackitem.NewBool(err == nil)
}
// VoteInternal votes from account h for validarors specified in pubs.
@ -361,19 +361,19 @@ func (n *NEO) GetRegisteredValidators(d dao.DAO) ([]state.Validator, error) {
return arr, nil
}
func (n *NEO) getRegisteredValidatorsCall(ic *interop.Context, _ []vm.StackItem) vm.StackItem {
func (n *NEO) getRegisteredValidatorsCall(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
validators, err := n.getRegisteredValidators(ic.DAO)
if err != nil {
panic(err)
}
arr := make([]vm.StackItem, len(validators))
arr := make([]stackitem.Item, len(validators))
for i := range validators {
arr[i] = vm.NewStructItem([]vm.StackItem{
vm.NewByteArrayItem([]byte(validators[i].Key)),
vm.NewBigIntegerItem(validators[i].Votes),
arr[i] = stackitem.NewStruct([]stackitem.Item{
stackitem.NewByteArray([]byte(validators[i].Key)),
stackitem.NewBigInteger(validators[i].Votes),
})
}
return vm.NewArrayItem(arr)
return stackitem.NewArray(arr)
}
// GetValidatorsInternal returns a list of current validators.
@ -430,7 +430,7 @@ func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (ke
return result, nil
}
func (n *NEO) getValidators(ic *interop.Context, _ []vm.StackItem) vm.StackItem {
func (n *NEO) getValidators(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
result, err := n.GetValidatorsInternal(ic.Chain, ic.DAO)
if err != nil {
panic(err)
@ -438,7 +438,7 @@ func (n *NEO) getValidators(ic *interop.Context, _ []vm.StackItem) vm.StackItem
return pubsToArray(result)
}
func (n *NEO) getNextBlockValidators(ic *interop.Context, _ []vm.StackItem) vm.StackItem {
func (n *NEO) getNextBlockValidators(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
result, err := n.GetNextBlockValidatorsInternal(ic.Chain, ic.DAO)
if err != nil {
panic(err)
@ -460,15 +460,15 @@ func (n *NEO) GetNextBlockValidatorsInternal(bc blockchainer.Blockchainer, d dao
return pubs, nil
}
func pubsToArray(pubs keys.PublicKeys) vm.StackItem {
arr := make([]vm.StackItem, len(pubs))
func pubsToArray(pubs keys.PublicKeys) stackitem.Item {
arr := make([]stackitem.Item, len(pubs))
for i := range pubs {
arr[i] = vm.NewByteArrayItem(pubs[i].Bytes())
arr[i] = stackitem.NewByteArray(pubs[i].Bytes())
}
return vm.NewArrayItem(arr)
return stackitem.NewArray(arr)
}
func toPublicKey(s vm.StackItem) *keys.PublicKey {
func toPublicKey(s stackitem.Item) *keys.PublicKey {
buf, err := s.TryBytes()
if err != nil {
panic(err)

View file

@ -7,11 +7,11 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"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"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// prefixAccount is the standard prefix used to store account data.
@ -86,20 +86,20 @@ func (c *nep5TokenNative) Initialize(_ *interop.Context) error {
return nil
}
func (c *nep5TokenNative) Name(_ *interop.Context, _ []vm.StackItem) vm.StackItem {
return vm.NewByteArrayItem([]byte(c.name))
func (c *nep5TokenNative) Name(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewByteArray([]byte(c.name))
}
func (c *nep5TokenNative) Symbol(_ *interop.Context, _ []vm.StackItem) vm.StackItem {
return vm.NewByteArrayItem([]byte(c.symbol))
func (c *nep5TokenNative) Symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewByteArray([]byte(c.symbol))
}
func (c *nep5TokenNative) Decimals(_ *interop.Context, _ []vm.StackItem) vm.StackItem {
return vm.NewBigIntegerItem(big.NewInt(c.decimals))
func (c *nep5TokenNative) Decimals(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewBigInteger(big.NewInt(c.decimals))
}
func (c *nep5TokenNative) TotalSupply(ic *interop.Context, _ []vm.StackItem) vm.StackItem {
return vm.NewBigIntegerItem(c.getTotalSupply(ic))
func (c *nep5TokenNative) TotalSupply(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewBigInteger(c.getTotalSupply(ic))
}
func (c *nep5TokenNative) getTotalSupply(ic *interop.Context) *big.Int {
@ -107,37 +107,37 @@ func (c *nep5TokenNative) getTotalSupply(ic *interop.Context) *big.Int {
if si == nil {
return big.NewInt(0)
}
return emit.BytesToInt(si.Value)
return bigint.FromBytes(si.Value)
}
func (c *nep5TokenNative) saveTotalSupply(ic *interop.Context, supply *big.Int) error {
si := &state.StorageItem{Value: emit.IntToBytes(supply)}
si := &state.StorageItem{Value: bigint.ToBytes(supply)}
return ic.DAO.PutStorageItem(c.Hash, totalSupplyKey, si)
}
func (c *nep5TokenNative) Transfer(ic *interop.Context, args []vm.StackItem) vm.StackItem {
func (c *nep5TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item {
from := toUint160(args[0])
to := toUint160(args[1])
amount := toBigInt(args[2])
err := c.transfer(ic, from, to, amount)
return vm.NewBoolItem(err == nil)
return stackitem.NewBool(err == nil)
}
func addrToStackItem(u *util.Uint160) vm.StackItem {
func addrToStackItem(u *util.Uint160) stackitem.Item {
if u == nil {
return vm.NullItem{}
return stackitem.Null{}
}
return vm.NewByteArrayItem(u.BytesBE())
return stackitem.NewByteArray(u.BytesBE())
}
func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) {
ne := state.NotificationEvent{
ScriptHash: c.Hash,
Item: vm.NewArrayItem([]vm.StackItem{
vm.NewByteArrayItem([]byte("Transfer")),
Item: stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray([]byte("Transfer")),
addrToStackItem(from),
addrToStackItem(to),
vm.NewBigIntegerItem(amount),
stackitem.NewBigInteger(amount),
}),
}
ic.Notifications = append(ic.Notifications, ne)
@ -197,14 +197,14 @@ func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, a
return nil
}
func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []vm.StackItem) vm.StackItem {
func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item) stackitem.Item {
h := toUint160(args[0])
bs, err := ic.DAO.GetNEP5Balances(h)
if err != nil {
panic(err)
}
balance := bs.Trackers[c.Hash].Balance
return vm.NewBigIntegerItem(big.NewInt(balance))
return stackitem.NewBigInteger(big.NewInt(balance))
}
func (c *nep5TokenNative) mint(ic *interop.Context, h util.Uint160, amount *big.Int) {
@ -269,7 +269,7 @@ func newMethodAndPrice(f interop.Method, price int64, flags smartcontract.CallFl
}
}
func toBigInt(s vm.StackItem) *big.Int {
func toBigInt(s stackitem.Item) *big.Int {
bi, err := s.TryInteger()
if err != nil {
panic(err)
@ -277,7 +277,7 @@ func toBigInt(s vm.StackItem) *big.Int {
return bi
}
func toUint160(s vm.StackItem) util.Uint160 {
func toUint160(s stackitem.Item) util.Uint160 {
buf, err := s.TryBytes()
if err != nil {
panic(err)

View file

@ -1,10 +1,11 @@
package native
import (
"errors"
"math/big"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
)
// MaxValidatorsVoted limits the number of validators that one can vote for.
@ -41,19 +42,25 @@ func (vc *ValidatorsCount) Bytes() []byte {
// EncodeBinary implements io.Serializable interface.
func (vc *ValidatorsCount) EncodeBinary(w *io.BinWriter) {
w.WriteVarUint(uint64(MaxValidatorsVoted))
for i := range vc {
w.WriteVarBytes(emit.IntToBytes(&vc[i]))
w.WriteVarBytes(bigint.ToBytes(&vc[i]))
}
}
// DecodeBinary implements io.Serializable interface.
func (vc *ValidatorsCount) DecodeBinary(r *io.BinReader) {
for i := range vc {
count := r.ReadVarUint()
if count < 0 || count > MaxValidatorsVoted {
r.Err = errors.New("invalid validators count")
return
}
for i := 0; i < int(count); i++ {
buf := r.ReadVarBytes()
if r.Err != nil {
return
}
vc[i] = *emit.BytesToInt(buf)
vc[i] = *bigint.FromBytes(buf)
}
}

View file

@ -10,8 +10,8 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
@ -67,7 +67,7 @@ func newTestNative() *testNative {
return tn
}
func (tn *testNative) sum(_ *interop.Context, args []vm.StackItem) vm.StackItem {
func (tn *testNative) sum(_ *interop.Context, args []stackitem.Item) stackitem.Item {
s1, err := args[0].TryInteger()
if err != nil {
panic(err)
@ -76,7 +76,7 @@ func (tn *testNative) sum(_ *interop.Context, args []vm.StackItem) vm.StackItem
if err != nil {
panic(err)
}
return vm.NewBigIntegerItem(s1.Add(s1, s2))
return stackitem.NewBigInteger(s1.Add(s1, s2))
}
func TestNativeContract_Invoke(t *testing.T) {

View file

@ -5,7 +5,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// NEP5BalanceState represents balance state of a NEP5-token.
@ -44,18 +44,27 @@ func (s *NEP5BalanceState) Bytes() []byte {
return w.Bytes()
}
func (s *NEP5BalanceState) toStackItem() stackitem.Item {
return stackitem.NewStruct([]stackitem.Item{stackitem.NewBigInteger(&s.Balance)})
}
func (s *NEP5BalanceState) fromStackItem(item stackitem.Item) {
s.Balance = *item.(*stackitem.Struct).Value().([]stackitem.Item)[0].Value().(*big.Int)
}
// EncodeBinary implements io.Serializable interface.
func (s *NEP5BalanceState) EncodeBinary(w *io.BinWriter) {
w.WriteVarBytes(emit.IntToBytes(&s.Balance))
si := s.toStackItem()
stackitem.EncodeBinaryStackItem(si, w)
}
// DecodeBinary implements io.Serializable interface.
func (s *NEP5BalanceState) DecodeBinary(r *io.BinReader) {
buf := r.ReadVarBytes()
si := stackitem.DecodeBinaryStackItem(r)
if r.Err != nil {
return
}
s.Balance = *emit.BytesToInt(buf)
s.fromStackItem(si)
}
// NEOBalanceStateFromBytes converts serialized NEOBalanceState to structure.
@ -85,14 +94,37 @@ func (s *NEOBalanceState) Bytes() []byte {
// EncodeBinary implements io.Serializable interface.
func (s *NEOBalanceState) EncodeBinary(w *io.BinWriter) {
s.NEP5BalanceState.EncodeBinary(w)
w.WriteU32LE(s.BalanceHeight)
w.WriteArray(s.Votes)
si := s.toStackItem()
stackitem.EncodeBinaryStackItem(si, w)
}
// DecodeBinary implements io.Serializable interface.
func (s *NEOBalanceState) DecodeBinary(r *io.BinReader) {
s.NEP5BalanceState.DecodeBinary(r)
s.BalanceHeight = r.ReadU32LE()
r.ReadArray(&s.Votes)
si := stackitem.DecodeBinaryStackItem(r)
if r.Err != nil {
return
}
s.fromStackItem(si)
}
func (s *NEOBalanceState) toStackItem() stackitem.Item {
result := s.NEP5BalanceState.toStackItem().(*stackitem.Struct)
result.Append(stackitem.NewBigInteger(big.NewInt(int64(s.BalanceHeight))))
votes := make([]stackitem.Item, len(s.Votes))
for i, v := range s.Votes {
votes[i] = stackitem.NewByteArray(v.Bytes())
}
result.Append(stackitem.NewArray(votes))
return result
}
func (s *NEOBalanceState) fromStackItem(item stackitem.Item) {
structItem := item.Value().([]stackitem.Item)
s.Balance = *structItem[0].Value().(*big.Int)
s.BalanceHeight = uint32(structItem[1].Value().(*big.Int).Int64())
votes := structItem[2].Value().([]stackitem.Item)
s.Votes = make([]*keys.PublicKey, len(votes))
for i, v := range votes {
s.Votes[i].DecodeBytes(v.Value().([]byte))
}
}

View file

@ -5,14 +5,14 @@ import (
"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/stackitem"
)
// NotificationEvent is a tuple of scripthash that emitted the StackItem as a
// NotificationEvent is a tuple of scripthash that emitted the Item as a
// notification and that item itself.
type NotificationEvent struct {
ScriptHash util.Uint160
Item vm.StackItem
Item stackitem.Item
}
// AppExecResult represent the result of the script execution, gathering together
@ -29,13 +29,13 @@ type AppExecResult struct {
// EncodeBinary implements the Serializable interface.
func (ne *NotificationEvent) EncodeBinary(w *io.BinWriter) {
ne.ScriptHash.EncodeBinary(w)
vm.EncodeBinaryStackItem(ne.Item, w)
stackitem.EncodeBinaryStackItem(ne.Item, w)
}
// DecodeBinary implements the Serializable interface.
func (ne *NotificationEvent) DecodeBinary(r *io.BinReader) {
ne.ScriptHash.DecodeBinary(r)
ne.Item = vm.DecodeBinaryStackItem(r)
ne.Item = stackitem.DecodeBinaryStackItem(r)
}
// EncodeBinary implements the Serializable interface.

View file

@ -6,13 +6,13 @@ import (
"github.com/nspcc-dev/neo-go/pkg/internal/random"
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
func TestEncodeDecodeNotificationEvent(t *testing.T) {
event := &NotificationEvent{
ScriptHash: random.Uint160(),
Item: vm.NewBoolItem(true),
Item: stackitem.NewBool(true),
}
testserdes.EncodeDecodeBinary(t, event, new(NotificationEvent))