mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-01-11 01:20:37 +00:00
*: 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": {
|
"blockchain": {
|
||||||
"GetAccount": "Neo.Blockchain.GetAccount",
|
"GetAccount": "Neo.Blockchain.GetAccount",
|
||||||
"GetAsset": "Neo.Blockchain.GetAsset",
|
|
||||||
"GetBlock": "Neo.Blockchain.GetBlock",
|
"GetBlock": "Neo.Blockchain.GetBlock",
|
||||||
"GetContract": "Neo.Blockchain.GetContract",
|
"GetContract": "Neo.Blockchain.GetContract",
|
||||||
"GetHeader": "Neo.Blockchain.GetHeader",
|
"GetHeader": "Neo.Blockchain.GetHeader",
|
||||||
|
@ -69,18 +68,6 @@ var syscalls = map[string]map[string]string{
|
||||||
"GetHash": "Neo.Transaction.GetHash",
|
"GetHash": "Neo.Transaction.GetHash",
|
||||||
"GetWitnesses": "Neo.Transaction.GetWitnesses",
|
"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": {
|
"contract": {
|
||||||
"GetScript": "Neo.Contract.GetScript",
|
"GetScript": "Neo.Contract.GetScript",
|
||||||
"IsPayable": "Neo.Contract.IsPayable",
|
"IsPayable": "Neo.Contract.IsPayable",
|
||||||
|
|
|
@ -938,17 +938,6 @@ func (bc *Blockchain) HeaderHeight() uint32 {
|
||||||
return uint32(bc.headerListLen() - 1)
|
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.
|
// GetContractState returns contract by its script hash.
|
||||||
func (bc *Blockchain) GetContractState(hash util.Uint160) *state.Contract {
|
func (bc *Blockchain) GetContractState(hash util.Uint160) *state.Contract {
|
||||||
contract, err := bc.dao.GetContractState(hash)
|
contract, err := bc.dao.GetContractState(hash)
|
||||||
|
|
|
@ -32,7 +32,6 @@ type Blockchainer interface {
|
||||||
CurrentBlockHash() util.Uint256
|
CurrentBlockHash() util.Uint256
|
||||||
HasBlock(util.Uint256) bool
|
HasBlock(util.Uint256) bool
|
||||||
HasTransaction(util.Uint256) bool
|
HasTransaction(util.Uint256) bool
|
||||||
GetAssetState(util.Uint256) *state.Asset
|
|
||||||
GetAccountState(util.Uint160) *state.Account
|
GetAccountState(util.Uint160) *state.Account
|
||||||
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
||||||
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
|
||||||
|
|
|
@ -23,7 +23,6 @@ type DAO interface {
|
||||||
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
|
||||||
GetAppExecResult(hash util.Uint256) (*state.AppExecResult, error)
|
GetAppExecResult(hash util.Uint256) (*state.AppExecResult, error)
|
||||||
GetAssetState(assetID util.Uint256) (*state.Asset, error)
|
|
||||||
GetBatch() *storage.MemBatch
|
GetBatch() *storage.MemBatch
|
||||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||||
GetContractState(hash util.Uint160) (*state.Contract, error)
|
GetContractState(hash util.Uint160) (*state.Contract, error)
|
||||||
|
@ -42,7 +41,6 @@ type DAO interface {
|
||||||
Persist() (int, error)
|
Persist() (int, error)
|
||||||
PutAccountState(as *state.Account) error
|
PutAccountState(as *state.Account) error
|
||||||
PutAppExecResult(aer *state.AppExecResult) error
|
PutAppExecResult(aer *state.AppExecResult) error
|
||||||
PutAssetState(as *state.Asset) error
|
|
||||||
PutContractState(cs *state.Contract) error
|
PutContractState(cs *state.Contract) error
|
||||||
PutCurrentHeader(hashAndIndex []byte) error
|
PutCurrentHeader(hashAndIndex []byte) error
|
||||||
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
|
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
|
||||||
|
@ -141,30 +139,6 @@ func (dao *Simple) putAccountState(as *state.Account, buf *io.BufBinWriter) erro
|
||||||
|
|
||||||
// -- end accounts.
|
// -- 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.
|
// -- start contracts.
|
||||||
|
|
||||||
// GetContractState returns contract state as recorded in the given
|
// 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/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/internal/random"
|
"github.com/nspcc-dev/neo-go/pkg/internal/random"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
@ -59,17 +58,6 @@ func TestPutAndGetAccountStateOrNew(t *testing.T) {
|
||||||
require.Equal(t, accountState.ScriptHash, gotAccount.ScriptHash)
|
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) {
|
func TestPutAndGetContractState(t *testing.T) {
|
||||||
dao := NewSimple(storage.NewMemoryStore())
|
dao := NewSimple(storage.NewMemoryStore())
|
||||||
contractState := &state.Contract{Script: []byte{}, ParamList: []smartcontract.ParamType{}}
|
contractState := &state.Contract{Script: []byte{}, ParamList: []smartcontract.ParamType{}}
|
||||||
|
|
|
@ -41,10 +41,6 @@ func getSyscallPrice(v *vm.VM, id uint32) util.Fixed8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
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
|
neoContractCreate = 0x6ea56cf6 // Neo.Contract.Create
|
||||||
neoContractMigrate = 0x90621b47 // Neo.Contract.Migrate
|
neoContractMigrate = 0x90621b47 // Neo.Contract.Migrate
|
||||||
antSharesContractCreate = 0x2a28d29b // AntShares.Contract.Create
|
antSharesContractCreate = 0x2a28d29b // AntShares.Contract.Create
|
||||||
|
@ -58,11 +54,6 @@ func getSyscallPrice(v *vm.VM, id uint32) util.Fixed8 {
|
||||||
estack := v.Estack()
|
estack := v.Estack()
|
||||||
|
|
||||||
switch id {
|
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:
|
case neoContractCreate, neoContractMigrate, antSharesContractCreate, antSharesContractMigrate:
|
||||||
return smartcontract.GetDeploymentPrice(smartcontract.PropertyState(estack.Peek(3).BigInt().Int64()))
|
return smartcontract.GetDeploymentPrice(smartcontract.PropertyState(estack.Peek(3).BigInt().Int64()))
|
||||||
case systemStoragePut, systemStoragePutEx, neoStoragePut, antSharesStoragePut:
|
case systemStoragePut, systemStoragePutEx, neoStoragePut, antSharesStoragePut:
|
||||||
|
|
|
@ -23,21 +23,6 @@ func TestGetPrice(t *testing.T) {
|
||||||
v := SpawnVM(systemInterop)
|
v := SpawnVM(systemInterop)
|
||||||
v.SetPriceGetter(getPrice)
|
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) {
|
t.Run("Neo.Contract.Create (no props)", func(t *testing.T) {
|
||||||
// Neo.Contract.Create: f66ca56e (requires push properties on fourth position)
|
// 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),
|
v.Load([]byte{byte(opcode.PUSH0), byte(opcode.PUSH0), byte(opcode.PUSH0), byte(opcode.PUSH0),
|
||||||
|
|
|
@ -4,19 +4,15 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"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/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
gherr "github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -28,15 +24,6 @@ const (
|
||||||
MaxContractParametersNum = 252
|
MaxContractParametersNum = 252
|
||||||
// MaxContractStringLen is the maximum length for contract metadata strings.
|
// MaxContractStringLen is the maximum length for contract metadata strings.
|
||||||
MaxContractStringLen = 252
|
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.
|
// headerGetVersion returns version from the header.
|
||||||
|
@ -156,21 +143,6 @@ func bcGetAccount(ic *interop.Context, v *vm.VM) error {
|
||||||
return nil
|
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.
|
// accountGetBalance returns balance for a given account.
|
||||||
func accountGetBalance(ic *interop.Context, v *vm.VM) error {
|
func accountGetBalance(ic *interop.Context, v *vm.VM) error {
|
||||||
accInterface := v.Estack().Pop().Value()
|
accInterface := v.Estack().Pop().Value()
|
||||||
|
@ -374,203 +346,6 @@ func contractMigrate(ic *interop.Context, v *vm.VM) error {
|
||||||
return contractDestroy(ic, v)
|
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.
|
// runtimeSerialize serializes top stack item into a ByteArray.
|
||||||
func runtimeSerialize(_ *interop.Context, v *vm.VM) error {
|
func runtimeSerialize(_ *interop.Context, v *vm.VM) error {
|
||||||
return vm.RuntimeSerialize(v)
|
return vm.RuntimeSerialize(v)
|
||||||
|
|
|
@ -27,14 +27,11 @@ import (
|
||||||
/* Missing tests:
|
/* Missing tests:
|
||||||
* TestTxGetWitnesses
|
* TestTxGetWitnesses
|
||||||
* TestBcGetAccount
|
* TestBcGetAccount
|
||||||
* TestBcGetAsset
|
|
||||||
* TestAccountGetBalance
|
* TestAccountGetBalance
|
||||||
* TestAccountIsStandard
|
* TestAccountIsStandard
|
||||||
* TestCreateContractStateFromVM
|
* TestCreateContractStateFromVM
|
||||||
* TestContractCreate
|
* TestContractCreate
|
||||||
* TestContractMigrate
|
* TestContractMigrate
|
||||||
* TestAssetCreate
|
|
||||||
* TestAssetRenew
|
|
||||||
* TestRuntimeSerialize
|
* TestRuntimeSerialize
|
||||||
* TestRuntimeDeserialize
|
* TestRuntimeDeserialize
|
||||||
*/
|
*/
|
||||||
|
@ -337,95 +334,7 @@ func TestContractIsPayable(t *testing.T) {
|
||||||
require.Equal(t, contractState.IsPayable(), isPayable)
|
require.Equal(t, contractState.IsPayable(), isPayable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAssetGetAdmin(t *testing.T) {
|
// Helper functions to create VM, InteropContext, TX, Account, Contract.
|
||||||
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.
|
|
||||||
|
|
||||||
func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
|
func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
|
||||||
v := vm.New()
|
v := vm.New()
|
||||||
|
@ -442,29 +351,6 @@ func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop
|
||||||
return v, tx, context, chain
|
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) {
|
func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) {
|
||||||
v := vm.New()
|
v := vm.New()
|
||||||
contractState := &state.Contract{
|
contractState := &state.Contract{
|
||||||
|
|
|
@ -105,23 +105,12 @@ var neoInterops = []interop.Function{
|
||||||
{Name: "Neo.Account.GetBalance", Func: accountGetBalance, Price: 1},
|
{Name: "Neo.Account.GetBalance", Func: accountGetBalance, Price: 1},
|
||||||
{Name: "Neo.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1},
|
{Name: "Neo.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1},
|
||||||
{Name: "Neo.Account.IsStandard", Func: accountIsStandard, Price: 100},
|
{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.GetData", Func: attrGetData, Price: 1},
|
||||||
{Name: "Neo.Attribute.GetUsage", Func: attrGetUsage, Price: 1},
|
{Name: "Neo.Attribute.GetUsage", Func: attrGetUsage, Price: 1},
|
||||||
{Name: "Neo.Block.GetTransaction", Func: blockGetTransaction, Price: 1},
|
{Name: "Neo.Block.GetTransaction", Func: blockGetTransaction, Price: 1},
|
||||||
{Name: "Neo.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
{Name: "Neo.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
||||||
{Name: "Neo.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
{Name: "Neo.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
||||||
{Name: "Neo.Blockchain.GetAccount", Func: bcGetAccount, Price: 100},
|
{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.GetBlock", Func: bcGetBlock, Price: 200},
|
||||||
{Name: "Neo.Blockchain.GetContract", Func: bcGetContract, Price: 100},
|
{Name: "Neo.Blockchain.GetContract", Func: bcGetContract, Price: 100},
|
||||||
{Name: "Neo.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
{Name: "Neo.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
||||||
|
@ -180,23 +169,12 @@ var neoInterops = []interop.Function{
|
||||||
// Old compatibility APIs.
|
// Old compatibility APIs.
|
||||||
{Name: "AntShares.Account.GetBalance", Func: accountGetBalance, Price: 1},
|
{Name: "AntShares.Account.GetBalance", Func: accountGetBalance, Price: 1},
|
||||||
{Name: "AntShares.Account.GetScriptHash", Func: accountGetScriptHash, 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.GetData", Func: attrGetData, Price: 1},
|
||||||
{Name: "AntShares.Attribute.GetUsage", Func: attrGetUsage, Price: 1},
|
{Name: "AntShares.Attribute.GetUsage", Func: attrGetUsage, Price: 1},
|
||||||
{Name: "AntShares.Block.GetTransaction", Func: blockGetTransaction, Price: 1},
|
{Name: "AntShares.Block.GetTransaction", Func: blockGetTransaction, Price: 1},
|
||||||
{Name: "AntShares.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
{Name: "AntShares.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
||||||
{Name: "AntShares.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
{Name: "AntShares.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
||||||
{Name: "AntShares.Blockchain.GetAccount", Func: bcGetAccount, Price: 100},
|
{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.GetBlock", Func: bcGetBlock, Price: 200},
|
||||||
{Name: "AntShares.Blockchain.GetContract", Func: bcGetContract, Price: 100},
|
{Name: "AntShares.Blockchain.GetContract", Func: bcGetContract, Price: 100},
|
||||||
{Name: "AntShares.Blockchain.GetHeader", Func: bcGetHeader, 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{
|
funcs := []func(*interop.Context, *vm.VM) error{
|
||||||
accountGetBalance,
|
accountGetBalance,
|
||||||
accountGetScriptHash,
|
accountGetScriptHash,
|
||||||
assetGetAdmin,
|
|
||||||
assetGetAmount,
|
|
||||||
assetGetAssetID,
|
|
||||||
assetGetAssetType,
|
|
||||||
assetGetAvailable,
|
|
||||||
assetGetIssuer,
|
|
||||||
assetGetOwner,
|
|
||||||
assetGetPrecision,
|
|
||||||
assetRenew,
|
|
||||||
attrGetData,
|
attrGetData,
|
||||||
attrGetUsage,
|
attrGetUsage,
|
||||||
blockGetTransaction,
|
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
|
DataBlock KeyPrefix = 0x01
|
||||||
DataTransaction KeyPrefix = 0x02
|
DataTransaction KeyPrefix = 0x02
|
||||||
STAccount KeyPrefix = 0x40
|
STAccount KeyPrefix = 0x40
|
||||||
STAsset KeyPrefix = 0x4c
|
|
||||||
STNotification KeyPrefix = 0x4d
|
STNotification KeyPrefix = 0x4d
|
||||||
STContract KeyPrefix = 0x50
|
STContract KeyPrefix = 0x50
|
||||||
STStorage KeyPrefix = 0x70
|
STStorage KeyPrefix = 0x70
|
||||||
|
|
|
@ -11,7 +11,6 @@ var (
|
||||||
DataBlock,
|
DataBlock,
|
||||||
DataTransaction,
|
DataTransaction,
|
||||||
STAccount,
|
STAccount,
|
||||||
STAsset,
|
|
||||||
STContract,
|
STContract,
|
||||||
STStorage,
|
STStorage,
|
||||||
IXHeaderHashList,
|
IXHeaderHashList,
|
||||||
|
@ -24,7 +23,6 @@ var (
|
||||||
0x01,
|
0x01,
|
||||||
0x02,
|
0x02,
|
||||||
0x40,
|
0x40,
|
||||||
0x4c,
|
|
||||||
0x50,
|
0x50,
|
||||||
0x70,
|
0x70,
|
||||||
0x80,
|
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 (
|
import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/account"
|
"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/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/header"
|
"github.com/nspcc-dev/neo-go/pkg/interop/header"
|
||||||
|
@ -73,11 +72,3 @@ func GetAccount(scriptHash []byte) account.Account {
|
||||||
func GetValidators() [][]byte {
|
func GetValidators() [][]byte {
|
||||||
return nil
|
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")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (chain testChain) GetAssetState(util.Uint256) *state.Asset {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
func (chain testChain) GetAccountState(util.Uint160) *state.Account {
|
func (chain testChain) GetAccountState(util.Uint160) *state.Account {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue