*: drop support for old on-chain assets
You no longer can transfer them, so creating/renewing/storing doesn't make much sense.
This commit is contained in:
parent
bf6435eeaa
commit
a986e2a064
20 changed files with 1 additions and 714 deletions
|
@ -40,7 +40,6 @@ var syscalls = map[string]map[string]string{
|
|||
},
|
||||
"blockchain": {
|
||||
"GetAccount": "Neo.Blockchain.GetAccount",
|
||||
"GetAsset": "Neo.Blockchain.GetAsset",
|
||||
"GetBlock": "Neo.Blockchain.GetBlock",
|
||||
"GetContract": "Neo.Blockchain.GetContract",
|
||||
"GetHeader": "Neo.Blockchain.GetHeader",
|
||||
|
@ -69,18 +68,6 @@ var syscalls = map[string]map[string]string{
|
|||
"GetHash": "Neo.Transaction.GetHash",
|
||||
"GetWitnesses": "Neo.Transaction.GetWitnesses",
|
||||
},
|
||||
"asset": {
|
||||
"Create": "Neo.Asset.Create",
|
||||
"GetAdmin": "Neo.Asset.GetAdmin",
|
||||
"GetAmount": "Neo.Asset.GetAmount",
|
||||
"GetAssetID": "Neo.Asset.GetAssetID",
|
||||
"GetAssetType": "Neo.Asset.GetAssetType",
|
||||
"GetAvailable": "Neo.Asset.GetAvailable",
|
||||
"GetIssuer": "Neo.Asset.GetIssuer",
|
||||
"GetOwner": "Neo.Asset.GetOwner",
|
||||
"GetPrecision": "Neo.Asset.GetPrecision",
|
||||
"Renew": "Neo.Asset.Renew",
|
||||
},
|
||||
"contract": {
|
||||
"GetScript": "Neo.Contract.GetScript",
|
||||
"IsPayable": "Neo.Contract.IsPayable",
|
||||
|
|
|
@ -938,17 +938,6 @@ func (bc *Blockchain) HeaderHeight() uint32 {
|
|||
return uint32(bc.headerListLen() - 1)
|
||||
}
|
||||
|
||||
// GetAssetState returns asset state from its assetID.
|
||||
func (bc *Blockchain) GetAssetState(assetID util.Uint256) *state.Asset {
|
||||
asset, err := bc.dao.GetAssetState(assetID)
|
||||
if asset == nil && err != storage.ErrKeyNotFound {
|
||||
bc.log.Warn("failed to get asset state",
|
||||
zap.Stringer("asset", assetID),
|
||||
zap.Error(err))
|
||||
}
|
||||
return asset
|
||||
}
|
||||
|
||||
// GetContractState returns contract by its script hash.
|
||||
func (bc *Blockchain) GetContractState(hash util.Uint160) *state.Contract {
|
||||
contract, err := bc.dao.GetContractState(hash)
|
||||
|
|
|
@ -32,7 +32,6 @@ type Blockchainer interface {
|
|||
CurrentBlockHash() util.Uint256
|
||||
HasBlock(util.Uint256) bool
|
||||
HasTransaction(util.Uint256) bool
|
||||
GetAssetState(util.Uint256) *state.Asset
|
||||
GetAccountState(util.Uint160) *state.Account
|
||||
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
||||
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
||||
|
|
|
@ -23,7 +23,6 @@ type DAO interface {
|
|||
GetAccountStateOrNew(hash util.Uint160) (*state.Account, error)
|
||||
GetAndDecode(entity io.Serializable, key []byte) error
|
||||
GetAppExecResult(hash util.Uint256) (*state.AppExecResult, error)
|
||||
GetAssetState(assetID util.Uint256) (*state.Asset, error)
|
||||
GetBatch() *storage.MemBatch
|
||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||
GetContractState(hash util.Uint160) (*state.Contract, error)
|
||||
|
@ -42,7 +41,6 @@ type DAO interface {
|
|||
Persist() (int, error)
|
||||
PutAccountState(as *state.Account) error
|
||||
PutAppExecResult(aer *state.AppExecResult) error
|
||||
PutAssetState(as *state.Asset) error
|
||||
PutContractState(cs *state.Contract) error
|
||||
PutCurrentHeader(hashAndIndex []byte) error
|
||||
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
|
||||
|
@ -141,30 +139,6 @@ func (dao *Simple) putAccountState(as *state.Account, buf *io.BufBinWriter) erro
|
|||
|
||||
// -- end accounts.
|
||||
|
||||
// -- start assets.
|
||||
|
||||
// GetAssetState returns given asset state as recorded in the given store.
|
||||
func (dao *Simple) GetAssetState(assetID util.Uint256) (*state.Asset, error) {
|
||||
asset := &state.Asset{}
|
||||
key := storage.AppendPrefix(storage.STAsset, assetID.BytesBE())
|
||||
err := dao.GetAndDecode(asset, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if asset.ID != assetID {
|
||||
return nil, fmt.Errorf("found asset id is not equal to expected")
|
||||
}
|
||||
return asset, nil
|
||||
}
|
||||
|
||||
// PutAssetState puts given asset state into the given store.
|
||||
func (dao *Simple) PutAssetState(as *state.Asset) error {
|
||||
key := storage.AppendPrefix(storage.STAsset, as.ID.BytesBE())
|
||||
return dao.Put(as, key)
|
||||
}
|
||||
|
||||
// -- end assets.
|
||||
|
||||
// -- start contracts.
|
||||
|
||||
// GetContractState returns contract state as recorded in the given
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"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/internal/random"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
|
@ -59,17 +58,6 @@ func TestPutAndGetAccountStateOrNew(t *testing.T) {
|
|||
require.Equal(t, accountState.ScriptHash, gotAccount.ScriptHash)
|
||||
}
|
||||
|
||||
func TestPutAndGetAssetState(t *testing.T) {
|
||||
dao := NewSimple(storage.NewMemoryStore())
|
||||
id := random.Uint256()
|
||||
assetState := &state.Asset{ID: id, Owner: keys.PublicKey{}}
|
||||
err := dao.PutAssetState(assetState)
|
||||
require.NoError(t, err)
|
||||
gotAssetState, err := dao.GetAssetState(id)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, assetState, gotAssetState)
|
||||
}
|
||||
|
||||
func TestPutAndGetContractState(t *testing.T) {
|
||||
dao := NewSimple(storage.NewMemoryStore())
|
||||
contractState := &state.Contract{Script: []byte{}, ParamList: []smartcontract.ParamType{}}
|
||||
|
|
|
@ -41,10 +41,6 @@ func getSyscallPrice(v *vm.VM, id uint32) util.Fixed8 {
|
|||
}
|
||||
|
||||
const (
|
||||
neoAssetCreate = 0x1fc6c583 // Neo.Asset.Create
|
||||
antSharesAssetCreate = 0x99025068 // AntShares.Asset.Create
|
||||
neoAssetRenew = 0x71908478 // Neo.Asset.Renew
|
||||
antSharesAssetRenew = 0xaf22447b // AntShares.Asset.Renew
|
||||
neoContractCreate = 0x6ea56cf6 // Neo.Contract.Create
|
||||
neoContractMigrate = 0x90621b47 // Neo.Contract.Migrate
|
||||
antSharesContractCreate = 0x2a28d29b // AntShares.Contract.Create
|
||||
|
@ -58,11 +54,6 @@ func getSyscallPrice(v *vm.VM, id uint32) util.Fixed8 {
|
|||
estack := v.Estack()
|
||||
|
||||
switch id {
|
||||
case neoAssetCreate, antSharesAssetCreate:
|
||||
return util.Fixed8FromInt64(5000)
|
||||
case neoAssetRenew, antSharesAssetRenew:
|
||||
arg := estack.Peek(1).BigInt().Int64()
|
||||
return util.Fixed8FromInt64(arg * 5000)
|
||||
case neoContractCreate, neoContractMigrate, antSharesContractCreate, antSharesContractMigrate:
|
||||
return smartcontract.GetDeploymentPrice(smartcontract.PropertyState(estack.Peek(3).BigInt().Int64()))
|
||||
case systemStoragePut, systemStoragePutEx, neoStoragePut, antSharesStoragePut:
|
||||
|
|
|
@ -23,21 +23,6 @@ func TestGetPrice(t *testing.T) {
|
|||
v := SpawnVM(systemInterop)
|
||||
v.SetPriceGetter(getPrice)
|
||||
|
||||
t.Run("Neo.Asset.Create", func(t *testing.T) {
|
||||
// Neo.Asset.Create: 83c5c61f
|
||||
v.Load([]byte{byte(opcode.SYSCALL), 0x83, 0xc5, 0xc6, 0x1f})
|
||||
checkGas(t, util.Fixed8FromInt64(5000), v)
|
||||
})
|
||||
|
||||
t.Run("Neo.Asset.Renew", func(t *testing.T) {
|
||||
// Neo.Asset.Renew: 78849071 (requires push 09 push 09 before)
|
||||
v.Load([]byte{byte(opcode.PUSH9), byte(opcode.PUSH9), byte(opcode.SYSCALL), 0x78, 0x84, 0x90, 0x71})
|
||||
require.NoError(t, v.StepInto()) // push 9
|
||||
require.NoError(t, v.StepInto()) // push 9
|
||||
|
||||
checkGas(t, util.Fixed8FromInt64(9*5000), v)
|
||||
})
|
||||
|
||||
t.Run("Neo.Contract.Create (no props)", func(t *testing.T) {
|
||||
// Neo.Contract.Create: f66ca56e (requires push properties on fourth position)
|
||||
v.Load([]byte{byte(opcode.PUSH0), byte(opcode.PUSH0), byte(opcode.PUSH0), byte(opcode.PUSH0),
|
||||
|
|
|
@ -4,19 +4,15 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"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/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"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"
|
||||
gherr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -28,15 +24,6 @@ const (
|
|||
MaxContractParametersNum = 252
|
||||
// MaxContractStringLen is the maximum length for contract metadata strings.
|
||||
MaxContractStringLen = 252
|
||||
// MaxAssetNameLen is the maximum length of asset name.
|
||||
MaxAssetNameLen = 1024
|
||||
// MaxAssetPrecision is the maximum precision of asset.
|
||||
MaxAssetPrecision = 8
|
||||
// BlocksPerYear is a multiplier for asset renewal.
|
||||
BlocksPerYear = 2000000
|
||||
// DefaultAssetLifetime is the default lifetime of an asset (which differs
|
||||
// from assets created by register tx).
|
||||
DefaultAssetLifetime = 1 + BlocksPerYear
|
||||
)
|
||||
|
||||
// headerGetVersion returns version from the header.
|
||||
|
@ -156,21 +143,6 @@ func bcGetAccount(ic *interop.Context, v *vm.VM) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// bcGetAsset returns an asset.
|
||||
func bcGetAsset(ic *interop.Context, v *vm.VM) error {
|
||||
asbytes := v.Estack().Pop().Bytes()
|
||||
ashash, err := util.Uint256DecodeBytesBE(asbytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
as, err := ic.DAO.GetAssetState(ashash)
|
||||
if err != nil {
|
||||
return errors.New("asset not found")
|
||||
}
|
||||
v.Estack().PushVal(vm.NewInteropItem(as))
|
||||
return nil
|
||||
}
|
||||
|
||||
// accountGetBalance returns balance for a given account.
|
||||
func accountGetBalance(ic *interop.Context, v *vm.VM) error {
|
||||
accInterface := v.Estack().Pop().Value()
|
||||
|
@ -374,203 +346,6 @@ func contractMigrate(ic *interop.Context, v *vm.VM) error {
|
|||
return contractDestroy(ic, v)
|
||||
}
|
||||
|
||||
// assetCreate creates an asset.
|
||||
func assetCreate(ic *interop.Context, v *vm.VM) error {
|
||||
if ic.Trigger != trigger.Application {
|
||||
return errors.New("can't create asset when not triggered by an application")
|
||||
}
|
||||
atype := transaction.AssetType(v.Estack().Pop().BigInt().Int64())
|
||||
switch atype {
|
||||
case transaction.Currency, transaction.Share, transaction.Invoice, transaction.Token:
|
||||
// ok
|
||||
default:
|
||||
return fmt.Errorf("wrong asset type: %x", atype)
|
||||
}
|
||||
name := string(v.Estack().Pop().Bytes())
|
||||
if len(name) > MaxAssetNameLen {
|
||||
return errors.New("too big name")
|
||||
}
|
||||
amount := util.Fixed8(v.Estack().Pop().BigInt().Int64())
|
||||
if amount == util.Fixed8(0) {
|
||||
return errors.New("asset amount can't be zero")
|
||||
}
|
||||
if amount < -util.Satoshi() {
|
||||
return errors.New("asset amount can't be negative (except special -Satoshi value")
|
||||
}
|
||||
if atype == transaction.Invoice && amount != -util.Satoshi() {
|
||||
return errors.New("invoice assets can only have -Satoshi amount")
|
||||
}
|
||||
precision := byte(v.Estack().Pop().BigInt().Int64())
|
||||
if precision > MaxAssetPrecision {
|
||||
return fmt.Errorf("can't have asset precision of more than %d", MaxAssetPrecision)
|
||||
}
|
||||
if atype == transaction.Share && precision != 0 {
|
||||
return errors.New("share assets can only have zero precision")
|
||||
}
|
||||
if amount != -util.Satoshi() && (int64(amount)%int64(math.Pow10(int(MaxAssetPrecision-precision))) != 0) {
|
||||
return errors.New("given asset amount has fractional component")
|
||||
}
|
||||
owner, err := keys.NewPublicKeyFromBytes(v.Estack().Pop().Bytes())
|
||||
if err != nil {
|
||||
return gherr.Wrap(err, "failed to get owner key")
|
||||
}
|
||||
if owner.IsInfinity() {
|
||||
return errors.New("can't have infinity as an owner key")
|
||||
}
|
||||
witnessOk, err := runtime.CheckKeyedWitness(ic, v, owner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !witnessOk {
|
||||
return errors.New("witness check didn't succeed")
|
||||
}
|
||||
admin, err := util.Uint160DecodeBytesBE(v.Estack().Pop().Bytes())
|
||||
if err != nil {
|
||||
return gherr.Wrap(err, "failed to get admin")
|
||||
}
|
||||
issuer, err := util.Uint160DecodeBytesBE(v.Estack().Pop().Bytes())
|
||||
if err != nil {
|
||||
return gherr.Wrap(err, "failed to get issuer")
|
||||
}
|
||||
asset := &state.Asset{
|
||||
ID: ic.Tx.Hash(),
|
||||
AssetType: atype,
|
||||
Name: name,
|
||||
Amount: amount,
|
||||
Precision: precision,
|
||||
Owner: *owner,
|
||||
Admin: admin,
|
||||
Issuer: issuer,
|
||||
Expiration: ic.Chain.BlockHeight() + DefaultAssetLifetime,
|
||||
}
|
||||
err = ic.DAO.PutAssetState(asset)
|
||||
if err != nil {
|
||||
return gherr.Wrap(err, "failed to Store asset")
|
||||
}
|
||||
v.Estack().PushVal(vm.NewInteropItem(asset))
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetAdmin returns asset admin.
|
||||
func assetGetAdmin(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(as.Admin.BytesBE())
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetAmount returns the overall amount of asset available.
|
||||
func assetGetAmount(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(int64(as.Amount))
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetAssetId returns the id of an asset.
|
||||
func assetGetAssetID(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(as.ID.BytesBE())
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetAssetType returns type of an asset.
|
||||
func assetGetAssetType(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(int(as.AssetType))
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetAvailable returns available (not yet issued) amount of asset.
|
||||
func assetGetAvailable(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(int(as.Available))
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetIssuer returns issuer of an asset.
|
||||
func assetGetIssuer(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(as.Issuer.BytesBE())
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetOwner returns owner of an asset.
|
||||
func assetGetOwner(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(as.Owner.Bytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetGetPrecision returns precision used to measure this asset.
|
||||
func assetGetPrecision(ic *interop.Context, v *vm.VM) error {
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
v.Estack().PushVal(int(as.Precision))
|
||||
return nil
|
||||
}
|
||||
|
||||
// assetRenew updates asset expiration date.
|
||||
func assetRenew(ic *interop.Context, v *vm.VM) error {
|
||||
if ic.Trigger != trigger.Application {
|
||||
return errors.New("can't create asset when not triggered by an application")
|
||||
}
|
||||
asInterface := v.Estack().Pop().Value()
|
||||
as, ok := asInterface.(*state.Asset)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not an asset state", as)
|
||||
}
|
||||
years := byte(v.Estack().Pop().BigInt().Int64())
|
||||
// Not sure why C# code regets an asset from the Store, but we also do it.
|
||||
asset, err := ic.DAO.GetAssetState(as.ID)
|
||||
if err != nil {
|
||||
return errors.New("can't renew non-existent asset")
|
||||
}
|
||||
if asset.Expiration < ic.Chain.BlockHeight()+1 {
|
||||
asset.Expiration = ic.Chain.BlockHeight() + 1
|
||||
}
|
||||
expiration := uint64(asset.Expiration) + uint64(years)*BlocksPerYear
|
||||
if expiration > math.MaxUint32 {
|
||||
expiration = math.MaxUint32
|
||||
}
|
||||
asset.Expiration = uint32(expiration)
|
||||
err = ic.DAO.PutAssetState(asset)
|
||||
if err != nil {
|
||||
return gherr.Wrap(err, "failed to Store asset")
|
||||
}
|
||||
v.Estack().PushVal(expiration)
|
||||
return nil
|
||||
}
|
||||
|
||||
// runtimeSerialize serializes top stack item into a ByteArray.
|
||||
func runtimeSerialize(_ *interop.Context, v *vm.VM) error {
|
||||
return vm.RuntimeSerialize(v)
|
||||
|
|
|
@ -27,14 +27,11 @@ import (
|
|||
/* Missing tests:
|
||||
* TestTxGetWitnesses
|
||||
* TestBcGetAccount
|
||||
* TestBcGetAsset
|
||||
* TestAccountGetBalance
|
||||
* TestAccountIsStandard
|
||||
* TestCreateContractStateFromVM
|
||||
* TestContractCreate
|
||||
* TestContractMigrate
|
||||
* TestAssetCreate
|
||||
* TestAssetRenew
|
||||
* TestRuntimeSerialize
|
||||
* TestRuntimeDeserialize
|
||||
*/
|
||||
|
@ -337,95 +334,7 @@ func TestContractIsPayable(t *testing.T) {
|
|||
require.Equal(t, contractState.IsPayable(), isPayable)
|
||||
}
|
||||
|
||||
func TestAssetGetAdmin(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetAdmin(context, v)
|
||||
require.NoError(t, err)
|
||||
admin := v.Estack().Pop().Value()
|
||||
require.Equal(t, assetState.Admin.BytesBE(), admin)
|
||||
}
|
||||
|
||||
func TestAssetGetAmount(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetAmount(context, v)
|
||||
require.NoError(t, err)
|
||||
amount := v.Estack().Pop().Value()
|
||||
require.Equal(t, big.NewInt(int64(assetState.Amount)), amount)
|
||||
}
|
||||
|
||||
func TestAssetGetAssetID(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetAssetID(context, v)
|
||||
require.NoError(t, err)
|
||||
assetID := v.Estack().Pop().Value()
|
||||
require.Equal(t, assetState.ID.BytesBE(), assetID)
|
||||
}
|
||||
|
||||
func TestAssetGetAssetType(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetAssetType(context, v)
|
||||
require.NoError(t, err)
|
||||
assetType := v.Estack().Pop().Value()
|
||||
require.Equal(t, big.NewInt(int64(assetState.AssetType)), assetType)
|
||||
}
|
||||
|
||||
func TestAssetGetAvailable(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetAvailable(context, v)
|
||||
require.NoError(t, err)
|
||||
available := v.Estack().Pop().Value()
|
||||
require.Equal(t, big.NewInt(int64(assetState.Available)), available)
|
||||
}
|
||||
|
||||
func TestAssetGetIssuer(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetIssuer(context, v)
|
||||
require.NoError(t, err)
|
||||
issuer := v.Estack().Pop().Value()
|
||||
require.Equal(t, assetState.Issuer.BytesBE(), issuer)
|
||||
}
|
||||
|
||||
func TestAssetGetOwner(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetOwner(context, v)
|
||||
require.NoError(t, err)
|
||||
owner := v.Estack().Pop().Value()
|
||||
require.Equal(t, assetState.Owner.Bytes(), owner)
|
||||
}
|
||||
|
||||
func TestAssetGetPrecision(t *testing.T) {
|
||||
v, assetState, context, chain := createVMAndAssetState(t)
|
||||
defer chain.Close()
|
||||
v.Estack().PushVal(vm.NewInteropItem(assetState))
|
||||
|
||||
err := assetGetPrecision(context, v)
|
||||
require.NoError(t, err)
|
||||
precision := v.Estack().Pop().Value()
|
||||
require.Equal(t, big.NewInt(int64(assetState.Precision)), precision)
|
||||
}
|
||||
|
||||
// Helper functions to create VM, InteropContext, TX, Account, Contract, Asset.
|
||||
// Helper functions to create VM, InteropContext, TX, Account, Contract.
|
||||
|
||||
func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
|
||||
v := vm.New()
|
||||
|
@ -442,29 +351,6 @@ func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop
|
|||
return v, tx, context, chain
|
||||
}
|
||||
|
||||
func createVMAndAssetState(t *testing.T) (*vm.VM, *state.Asset, *interop.Context, *Blockchain) {
|
||||
v := vm.New()
|
||||
assetState := &state.Asset{
|
||||
ID: util.Uint256{},
|
||||
AssetType: transaction.GoverningToken,
|
||||
Name: "TestAsset",
|
||||
Amount: 1,
|
||||
Available: 2,
|
||||
Precision: 1,
|
||||
FeeMode: 1,
|
||||
FeeAddress: random.Uint160(),
|
||||
Owner: keys.PublicKey{X: big.NewInt(1), Y: big.NewInt(1)},
|
||||
Admin: random.Uint160(),
|
||||
Issuer: random.Uint160(),
|
||||
Expiration: 10,
|
||||
IsFrozen: false,
|
||||
}
|
||||
|
||||
chain := newTestChain(t)
|
||||
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), nil, nil)
|
||||
return v, assetState, context, chain
|
||||
}
|
||||
|
||||
func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) {
|
||||
v := vm.New()
|
||||
contractState := &state.Contract{
|
||||
|
|
|
@ -105,23 +105,12 @@ var neoInterops = []interop.Function{
|
|||
{Name: "Neo.Account.GetBalance", Func: accountGetBalance, Price: 1},
|
||||
{Name: "Neo.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1},
|
||||
{Name: "Neo.Account.IsStandard", Func: accountIsStandard, Price: 100},
|
||||
{Name: "Neo.Asset.Create", Func: assetCreate, Price: 0},
|
||||
{Name: "Neo.Asset.GetAdmin", Func: assetGetAdmin, Price: 1},
|
||||
{Name: "Neo.Asset.GetAmount", Func: assetGetAmount, Price: 1},
|
||||
{Name: "Neo.Asset.GetAssetId", Func: assetGetAssetID, Price: 1},
|
||||
{Name: "Neo.Asset.GetAssetType", Func: assetGetAssetType, Price: 1},
|
||||
{Name: "Neo.Asset.GetAvailable", Func: assetGetAvailable, Price: 1},
|
||||
{Name: "Neo.Asset.GetIssuer", Func: assetGetIssuer, Price: 1},
|
||||
{Name: "Neo.Asset.GetOwner", Func: assetGetOwner, Price: 1},
|
||||
{Name: "Neo.Asset.GetPrecision", Func: assetGetPrecision, Price: 1},
|
||||
{Name: "Neo.Asset.Renew", Func: assetRenew, Price: 0},
|
||||
{Name: "Neo.Attribute.GetData", Func: attrGetData, Price: 1},
|
||||
{Name: "Neo.Attribute.GetUsage", Func: attrGetUsage, Price: 1},
|
||||
{Name: "Neo.Block.GetTransaction", Func: blockGetTransaction, Price: 1},
|
||||
{Name: "Neo.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
||||
{Name: "Neo.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
||||
{Name: "Neo.Blockchain.GetAccount", Func: bcGetAccount, Price: 100},
|
||||
{Name: "Neo.Blockchain.GetAsset", Func: bcGetAsset, Price: 100},
|
||||
{Name: "Neo.Blockchain.GetBlock", Func: bcGetBlock, Price: 200},
|
||||
{Name: "Neo.Blockchain.GetContract", Func: bcGetContract, Price: 100},
|
||||
{Name: "Neo.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
||||
|
@ -180,23 +169,12 @@ var neoInterops = []interop.Function{
|
|||
// Old compatibility APIs.
|
||||
{Name: "AntShares.Account.GetBalance", Func: accountGetBalance, Price: 1},
|
||||
{Name: "AntShares.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1},
|
||||
{Name: "AntShares.Asset.Create", Func: assetCreate, Price: 0},
|
||||
{Name: "AntShares.Asset.GetAdmin", Func: assetGetAdmin, Price: 1},
|
||||
{Name: "AntShares.Asset.GetAmount", Func: assetGetAmount, Price: 1},
|
||||
{Name: "AntShares.Asset.GetAssetId", Func: assetGetAssetID, Price: 1},
|
||||
{Name: "AntShares.Asset.GetAssetType", Func: assetGetAssetType, Price: 1},
|
||||
{Name: "AntShares.Asset.GetAvailable", Func: assetGetAvailable, Price: 1},
|
||||
{Name: "AntShares.Asset.GetIssuer", Func: assetGetIssuer, Price: 1},
|
||||
{Name: "AntShares.Asset.GetOwner", Func: assetGetOwner, Price: 1},
|
||||
{Name: "AntShares.Asset.GetPrecision", Func: assetGetPrecision, Price: 1},
|
||||
{Name: "AntShares.Asset.Renew", Func: assetRenew, Price: 0},
|
||||
{Name: "AntShares.Attribute.GetData", Func: attrGetData, Price: 1},
|
||||
{Name: "AntShares.Attribute.GetUsage", Func: attrGetUsage, Price: 1},
|
||||
{Name: "AntShares.Block.GetTransaction", Func: blockGetTransaction, Price: 1},
|
||||
{Name: "AntShares.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
||||
{Name: "AntShares.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
||||
{Name: "AntShares.Blockchain.GetAccount", Func: bcGetAccount, Price: 100},
|
||||
{Name: "AntShares.Blockchain.GetAsset", Func: bcGetAsset, Price: 100},
|
||||
{Name: "AntShares.Blockchain.GetBlock", Func: bcGetBlock, Price: 200},
|
||||
{Name: "AntShares.Blockchain.GetContract", Func: bcGetContract, Price: 100},
|
||||
{Name: "AntShares.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
||||
|
|
|
@ -34,15 +34,6 @@ func TestUnexpectedNonInterops(t *testing.T) {
|
|||
funcs := []func(*interop.Context, *vm.VM) error{
|
||||
accountGetBalance,
|
||||
accountGetScriptHash,
|
||||
assetGetAdmin,
|
||||
assetGetAmount,
|
||||
assetGetAssetID,
|
||||
assetGetAssetType,
|
||||
assetGetAvailable,
|
||||
assetGetIssuer,
|
||||
assetGetOwner,
|
||||
assetGetPrecision,
|
||||
assetRenew,
|
||||
attrGetData,
|
||||
attrGetUsage,
|
||||
blockGetTransaction,
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"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/util"
|
||||
)
|
||||
|
||||
const feeMode = 0x0
|
||||
|
||||
// Asset represents the state of an NEO registered Asset.
|
||||
type Asset struct {
|
||||
ID util.Uint256
|
||||
AssetType transaction.AssetType
|
||||
Name string
|
||||
Amount util.Fixed8
|
||||
Available util.Fixed8
|
||||
Precision uint8
|
||||
FeeMode uint8
|
||||
FeeAddress util.Uint160
|
||||
Owner keys.PublicKey
|
||||
Admin util.Uint160
|
||||
Issuer util.Uint160
|
||||
Expiration uint32
|
||||
IsFrozen bool
|
||||
}
|
||||
|
||||
// DecodeBinary implements Serializable interface.
|
||||
func (a *Asset) DecodeBinary(br *io.BinReader) {
|
||||
br.ReadBytes(a.ID[:])
|
||||
a.AssetType = transaction.AssetType(br.ReadB())
|
||||
|
||||
a.Name = br.ReadString()
|
||||
|
||||
a.Amount.DecodeBinary(br)
|
||||
a.Available.DecodeBinary(br)
|
||||
a.Precision = uint8(br.ReadB())
|
||||
a.FeeMode = uint8(br.ReadB())
|
||||
a.FeeAddress.DecodeBinary(br)
|
||||
|
||||
a.Owner.DecodeBinary(br)
|
||||
a.Admin.DecodeBinary(br)
|
||||
a.Issuer.DecodeBinary(br)
|
||||
a.Expiration = br.ReadU32LE()
|
||||
a.IsFrozen = br.ReadBool()
|
||||
}
|
||||
|
||||
// EncodeBinary implements Serializable interface.
|
||||
func (a *Asset) EncodeBinary(bw *io.BinWriter) {
|
||||
bw.WriteBytes(a.ID[:])
|
||||
bw.WriteB(byte(a.AssetType))
|
||||
bw.WriteString(a.Name)
|
||||
a.Amount.EncodeBinary(bw)
|
||||
a.Available.EncodeBinary(bw)
|
||||
bw.WriteB(byte(a.Precision))
|
||||
bw.WriteB(byte(a.FeeMode))
|
||||
a.FeeAddress.EncodeBinary(bw)
|
||||
|
||||
a.Owner.EncodeBinary(bw)
|
||||
|
||||
a.Admin.EncodeBinary(bw)
|
||||
a.Issuer.EncodeBinary(bw)
|
||||
bw.WriteU32LE(a.Expiration)
|
||||
bw.WriteBool(a.IsFrozen)
|
||||
}
|
||||
|
||||
// GetName returns the asset name based on its type.
|
||||
func (a *Asset) GetName() string {
|
||||
|
||||
if a.AssetType == transaction.GoverningToken {
|
||||
return "NEO"
|
||||
} else if a.AssetType == transaction.UtilityToken {
|
||||
return "NEOGas"
|
||||
}
|
||||
|
||||
return a.Name
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"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/internal/random"
|
||||
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncodeDecodeAssetState(t *testing.T) {
|
||||
asset := &Asset{
|
||||
ID: random.Uint256(),
|
||||
AssetType: transaction.Token,
|
||||
Name: "super cool token",
|
||||
Amount: util.Fixed8(1000000),
|
||||
Available: util.Fixed8(100),
|
||||
Precision: 0,
|
||||
FeeMode: feeMode,
|
||||
Owner: keys.PublicKey{},
|
||||
Admin: random.Uint160(),
|
||||
Issuer: random.Uint160(),
|
||||
Expiration: 10,
|
||||
IsFrozen: false,
|
||||
}
|
||||
|
||||
testserdes.EncodeDecodeBinary(t, asset, new(Asset))
|
||||
}
|
||||
|
||||
func TestAssetState_GetName_NEO(t *testing.T) {
|
||||
asset := &Asset{AssetType: transaction.GoverningToken}
|
||||
assert.Equal(t, "NEO", asset.GetName())
|
||||
}
|
||||
|
||||
func TestAssetState_GetName_NEOGas(t *testing.T) {
|
||||
asset := &Asset{AssetType: transaction.UtilityToken}
|
||||
assert.Equal(t, "NEOGas", asset.GetName())
|
||||
}
|
|
@ -10,7 +10,6 @@ const (
|
|||
DataBlock KeyPrefix = 0x01
|
||||
DataTransaction KeyPrefix = 0x02
|
||||
STAccount KeyPrefix = 0x40
|
||||
STAsset KeyPrefix = 0x4c
|
||||
STNotification KeyPrefix = 0x4d
|
||||
STContract KeyPrefix = 0x50
|
||||
STStorage KeyPrefix = 0x70
|
||||
|
|
|
@ -11,7 +11,6 @@ var (
|
|||
DataBlock,
|
||||
DataTransaction,
|
||||
STAccount,
|
||||
STAsset,
|
||||
STContract,
|
||||
STStorage,
|
||||
IXHeaderHashList,
|
||||
|
@ -24,7 +23,6 @@ var (
|
|||
0x01,
|
||||
0x02,
|
||||
0x40,
|
||||
0x4c,
|
||||
0x50,
|
||||
0x70,
|
||||
0x80,
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package transaction
|
||||
|
||||
// AssetType represents a NEO asset type.
|
||||
type AssetType uint8
|
||||
|
||||
// Valid asset types.
|
||||
const (
|
||||
CreditFlag AssetType = 0x40
|
||||
DutyFlag AssetType = 0x80
|
||||
GoverningToken AssetType = 0x00
|
||||
UtilityToken AssetType = 0x01
|
||||
Currency AssetType = 0x08
|
||||
Share AssetType = DutyFlag | 0x10
|
||||
Invoice AssetType = DutyFlag | 0x18
|
||||
Token AssetType = CreditFlag | 0x20
|
||||
)
|
|
@ -1,9 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import "github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
||||
// Result represents the Result of a transaction.
|
||||
type Result struct {
|
||||
AssetID util.Uint256
|
||||
Amount util.Fixed8
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
Package asset provides functions to work with regular UTXO assets (like NEO or GAS).
|
||||
Mostly these are getters for Asset structure, but you can also create new assets
|
||||
and renew them (although it's recommended to use NEP-5 standard for new tokens).
|
||||
*/
|
||||
package asset
|
||||
|
||||
// Asset represents NEO asset type that is used in interop functions, it's
|
||||
// an opaque data structure that you can get data from only using functions from
|
||||
// this package. It's similar in function to the Asset class in the Neo .net
|
||||
// framework. To be able to use it you either need to get an existing Asset via
|
||||
// blockchain.GetAsset function or create a new one via Create.
|
||||
type Asset struct{}
|
||||
|
||||
// GetAssetID returns ID (256-bit ID of Register transaction for this asset in BE
|
||||
// representation) of the given asset. It uses `Neo.Asset.GetAssetId` syscall
|
||||
// internally.
|
||||
func GetAssetID(a Asset) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAssetType returns type of the given asset as a byte value. The value
|
||||
// returned can be interpreted as a bit field with the following meaning:
|
||||
// CreditFlag = 0x40
|
||||
// DutyFlag = 0x80
|
||||
// SystemShare = 0x00
|
||||
// SystemCoin = 0x01
|
||||
// Currency = 0x08
|
||||
// Share = DutyFlag | 0x10
|
||||
// Invoice = DutyFlag | 0x18
|
||||
// Token = CreditFlag | 0x20
|
||||
// It uses `Neo.Asset.GetAssetType` syscall internally.
|
||||
func GetAssetType(a Asset) byte {
|
||||
return 0x00
|
||||
}
|
||||
|
||||
// GetAmount returns the total amount of the given asset as an integer
|
||||
// multiplied by 10⁸. This value is the maximum possible circulating quantity of
|
||||
// Asset. The function uses `Neo.Asset.GetAmount` syscall internally.
|
||||
func GetAmount(a Asset) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetAvailable returns the amount of Asset currently available on the
|
||||
// blockchain. It uses the same encoding as the result of GetAmount and its
|
||||
// value can never exceed the value returned by GetAmount. This function uses
|
||||
// `Neo.Asset.GetAvailable` syscall internally.
|
||||
func GetAvailable(a Asset) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetPrecision returns precision of the given Asset. It uses
|
||||
// `Neo.Asset.GetPrecision` syscall internally.
|
||||
func GetPrecision(a Asset) byte {
|
||||
return 0x00
|
||||
}
|
||||
|
||||
// GetOwner returns the owner of the given Asset. It's represented as a
|
||||
// serialized (in compressed form) public key (33 bytes long). This function
|
||||
// uses `Neo.Asset.GetOwner` syscall internally.
|
||||
func GetOwner(a Asset) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAdmin returns the admin of the given Asset represented as a 160 bit hash
|
||||
// in BE form (contract script hash). Admin can modify attributes of this Asset.
|
||||
// This function uses `Neo.Asset.GetAdmin` syscall internally.
|
||||
func GetAdmin(a Asset) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetIssuer returns the issuer of the given Asset represented as a 160 bit hash
|
||||
// in BE form (contract script hash). Issuer can issue new tokens for this Asset.
|
||||
// This function uses `Neo.Asset.GetIssuer` syscall internally.
|
||||
func GetIssuer(a Asset) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create registers a new asset on the blockchain (similar to old Register
|
||||
// transaction). `assetType` parameter has the same set of possible values as
|
||||
// GetAssetType result, `amount` must be multiplied by 10⁸, `precision` limits
|
||||
// the smallest possible amount of new Asset to 10⁻ⁿ (where n is precision which
|
||||
// can't exceed 8), `owner` is a public key of the owner in compressed serialized
|
||||
// form (33 bytes), `admin` and `issuer` should be represented as 20-byte slices
|
||||
// storing 160-bit hash in BE form. Created Asset is set to expire in one year,
|
||||
// so you need to renew it in time. If successful, this function returns a new
|
||||
// Asset. It uses `Neo.Asset.Create` syscall internally.
|
||||
func Create(assetType byte, name string, amount int, precision byte, owner, admin, issuer []byte) Asset {
|
||||
return Asset{}
|
||||
}
|
||||
|
||||
// Renew renews (make available for use) existing asset by the specified number
|
||||
// of years. It returns the last block number when this asset will be active.
|
||||
// It uses `Neo.Asset.Renew` syscall internally.
|
||||
func Renew(asset Asset, years int) int {
|
||||
return 0
|
||||
}
|
|
@ -5,7 +5,6 @@ package blockchain
|
|||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/account"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/asset"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/header"
|
||||
|
@ -73,11 +72,3 @@ func GetAccount(scriptHash []byte) account.Account {
|
|||
func GetValidators() [][]byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAsset returns asset found by the given asset ID (256 bit in BE format
|
||||
// represented as a slice of 32 bytes). Refer to the `asset` package for
|
||||
// possible uses of returned structure. This function uses
|
||||
// `Neo.Blockchain.GetAsset` syscall.
|
||||
func GetAsset(assetID []byte) asset.Asset {
|
||||
return asset.Asset{}
|
||||
}
|
||||
|
|
|
@ -73,9 +73,6 @@ func (chain testChain) GetHeader(hash util.Uint256) (*block.Header, error) {
|
|||
panic("TODO")
|
||||
}
|
||||
|
||||
func (chain testChain) GetAssetState(util.Uint256) *state.Asset {
|
||||
panic("TODO")
|
||||
}
|
||||
func (chain testChain) GetAccountState(util.Uint160) *state.Account {
|
||||
panic("TODO")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue