Merge pull request #1093 from nspcc-dev/fix-some-inconsistencies-wrt-sharp

Fix some inconsistencies wrt sharp
This commit is contained in:
Roman Khimov 2020-06-24 10:47:16 +03:00 committed by GitHub
commit 5d51ceaeac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 289 additions and 176 deletions

View file

@ -9,7 +9,6 @@ import (
"path/filepath"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/util"
)
type dump []blockDump
@ -26,26 +25,24 @@ type storageOp struct {
Value string `json:"value,omitempty"`
}
// NEO has some differences of key storing.
// out format: script hash in LE + key
// neo format: script hash in BE + byte(0) + key with 0 between every 16 bytes, padded to len 16.
// NEO has some differences of key storing (that should go away post-preview2).
// ours format: contract's ID (uint32le) + key
// theirs format: contract's ID (uint32le) + key with 16 between every 16 bytes, padded to len 16.
func toNeoStorageKey(key []byte) []byte {
if len(key) < util.Uint160Size {
if len(key) < 4 {
panic("invalid key in storage")
}
var nkey []byte
for i := util.Uint160Size - 1; i >= 0; i-- {
nkey = append(nkey, key[i])
}
key = key[util.Uint160Size:]
// Prefix is a contract's ID in LE.
nkey := make([]byte, 4, len(key))
copy(nkey, key[:4])
key = key[4:]
index := 0
remain := len(key)
for remain >= 16 {
nkey = append(nkey, key[index:index+16]...)
nkey = append(nkey, 0)
nkey = append(nkey, 16)
index += 16
remain -= 16
}
@ -59,7 +56,7 @@ func toNeoStorageKey(key []byte) []byte {
nkey = append(nkey, 0)
}
nkey = append(nkey, byte(padding))
nkey = append(nkey, byte(remain))
return nkey
}
@ -84,7 +81,7 @@ func batchToMap(index uint32, batch *storage.MemBatch) blockDump {
ops = append(ops, storageOp{
State: op,
Key: hex.EncodeToString(key),
Value: "00" + hex.EncodeToString(batch.Put[i].Value),
Value: hex.EncodeToString(batch.Put[i].Value),
})
}

View file

@ -236,7 +236,11 @@ type Token struct {
func (t Token) AddToCirculation(amount int) bool {
ctx := storage.Context()
inCirc := storage.Get(ctx, "in_circ").(int)
var inCirc int
val := storage.Get(ctx, "in_circ")
if val != nil {
inCirc = val.(int)
}
inCirc += amount
storage.Put(ctx, "in_circ", inCirc)
return true

View file

@ -71,15 +71,25 @@ func NewTokenConfig() TokenConfig {
}
}
// getIntFromDB is a helper that checks for nil result of storage.Get and returns
// zero as the default value.
func getIntFromDB(ctx storage.Context, key []byte) int {
var res int
val := storage.Get(ctx, key)
if val != nil {
res = val.(int)
}
return res
}
// InCirculation return the amount of total tokens that are in circulation.
func (t TokenConfig) InCirculation(ctx storage.Context) int {
amount := storage.Get(ctx, t.CirculationKey)
return amount.(int)
return getIntFromDB(ctx, t.CirculationKey)
}
// AddToCirculation sets the given amount as "in circulation" in the storage.
func (t TokenConfig) AddToCirculation(ctx storage.Context, amount int) bool {
supply := storage.Get(ctx, t.CirculationKey).(int)
supply := getIntFromDB(ctx, t.CirculationKey)
supply += amount
storage.Put(ctx, t.CirculationKey, supply)
return true
@ -88,8 +98,8 @@ func (t TokenConfig) AddToCirculation(ctx storage.Context, amount int) bool {
// TokenSaleAvailableAmount returns the total amount of available tokens left
// to be distributed.
func (t TokenConfig) TokenSaleAvailableAmount(ctx storage.Context) int {
inCirc := storage.Get(ctx, t.CirculationKey)
return t.TotalSupply - inCirc.(int)
inCirc := getIntFromDB(ctx, t.CirculationKey)
return t.TotalSupply - inCirc
}
// Main smart contract entry point.
@ -128,11 +138,11 @@ func handleOperation(op string, args []interface{}, ctx storage.Context, cfg Tok
return cfg.Symbol
}
if op == "totalSupply" {
return storage.Get(ctx, cfg.CirculationKey)
return getIntFromDB(ctx, cfg.CirculationKey)
}
if op == "balanceOf" {
if len(args) == 1 {
return storage.Get(ctx, args[0].([]byte))
return getIntFromDB(ctx, args[0].([]byte))
}
}
if op == "transfer" {
@ -177,7 +187,7 @@ func transfer(cfg TokenConfig, ctx storage.Context, from, to []byte, amount int)
if amount <= 0 || len(to) != 20 || !runtime.CheckWitness(from) {
return false
}
amountFrom := storage.Get(ctx, from).(int)
amountFrom := getIntFromDB(ctx, from)
if amountFrom < amount {
return false
}
@ -187,7 +197,7 @@ func transfer(cfg TokenConfig, ctx storage.Context, from, to []byte, amount int)
diff := amountFrom - amount
storage.Put(ctx, from, diff)
}
amountTo := storage.Get(ctx, to).(int)
amountTo := getIntFromDB(ctx, to)
totalAmountTo := amountTo + amount
storage.Put(ctx, to, totalAmountTo)
return true
@ -201,15 +211,15 @@ func transferFrom(cfg TokenConfig, ctx storage.Context, from, to []byte, amount
if len(availableKey) != 40 {
return false
}
availableTo := storage.Get(ctx, availableKey).(int)
availableTo := getIntFromDB(ctx, availableKey)
if availableTo < amount {
return false
}
fromBalance := storage.Get(ctx, from).(int)
fromBalance := getIntFromDB(ctx, from)
if fromBalance < amount {
return false
}
toBalance := storage.Get(ctx, to).(int)
toBalance := getIntFromDB(ctx, to)
newFromBalance := fromBalance - amount
newToBalance := toBalance + amount
storage.Put(ctx, to, newToBalance)
@ -231,7 +241,7 @@ func approve(ctx storage.Context, owner, spender []byte, amount int) bool {
if len(spender) != 20 {
return false
}
toSpend := storage.Get(ctx, owner).(int)
toSpend := getIntFromDB(ctx, owner)
if toSpend < amount {
return false
}
@ -246,5 +256,5 @@ func approve(ctx storage.Context, owner, spender []byte, amount int) bool {
func allowance(ctx storage.Context, from, to []byte) int {
key := append(from, to...)
return storage.Get(ctx, key).(int)
return getIntFromDB(ctx, key)
}

View file

@ -22,14 +22,25 @@ type Token struct {
CirculationKey string
}
// getIntFromDB is a helper that checks for nil result of storage.Get and returns
// zero as the default value.
func getIntFromDB(ctx storage.Context, key []byte) int {
var res int
val := storage.Get(ctx, key)
if val != nil {
res = val.(int)
}
return res
}
// GetSupply gets the token totalSupply value from VM storage
func (t Token) GetSupply(ctx storage.Context) interface{} {
return storage.Get(ctx, t.CirculationKey)
return getIntFromDB(ctx, []byte(t.CirculationKey))
}
// BalanceOf gets the token balance of a specific address
func (t Token) BalanceOf(ctx storage.Context, hodler []byte) interface{} {
return storage.Get(ctx, hodler)
return getIntFromDB(ctx, hodler)
}
// Transfer token from one user to another
@ -48,7 +59,7 @@ func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int)
storage.Put(ctx, from, diff)
}
amountTo := storage.Get(ctx, to).(int)
amountTo := getIntFromDB(ctx, to)
totalAmountTo := amountTo + amount
storage.Put(ctx, to, totalAmountTo)
runtime.Notify("transfer", from, to, amount)
@ -61,7 +72,7 @@ func (t Token) CanTransfer(ctx storage.Context, from []byte, to []byte, amount i
return -1
}
amountFrom := storage.Get(ctx, from).(int)
amountFrom := getIntFromDB(ctx, from)
if amountFrom < amount {
return -1
}
@ -98,8 +109,8 @@ func (t Token) Mint(ctx storage.Context, to []byte) bool {
if !IsUsableAddress(t.Owner) {
return false
}
minted := storage.Get(ctx, []byte("minted")).(bool)
if minted {
minted := storage.Get(ctx, []byte("minted"))
if minted != nil && minted.(bool) == true {
return false
}

View file

@ -659,8 +659,26 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil
}
var checkForNull bool
if isExprNil(n.X) {
checkForNull = true
} else {
ast.Walk(c, n.X)
}
if isExprNil(n.Y) {
checkForNull = true
} else {
ast.Walk(c, n.Y)
}
if checkForNull {
emit.Opcode(c.prog.BinWriter, opcode.ISNULL)
if n.Op == token.NEQ {
emit.Opcode(c.prog.BinWriter, opcode.NOT)
}
return nil
}
switch {
case n.Op == token.ADD:

View file

@ -0,0 +1,55 @@
package compiler_test
import (
"math/big"
"testing"
)
var nilTestCases = []testCase{
{
"nil check positive right",
`
package foo
func Main() int {
var t interface{}
if t == nil {
return 1
}
return 2
}
`,
big.NewInt(1),
},
{
"nil check negative right",
`
package foo
func Main() int {
t := []byte{}
if t == nil {
return 1
}
return 2
}
`,
big.NewInt(2),
},
{
"nil check positive left",
`
package foo
func Main() int {
var t interface{}
if nil == t {
return 1
}
return 2
}
`,
big.NewInt(1),
},
}
func TestNil(t *testing.T) {
runTestCases(t, nilTestCases)
}

View file

@ -213,7 +213,7 @@ func newTestService(t *testing.T) *service {
}
func getTestValidator(i int) (*privateKey, *publicKey) {
key := testchain.PrivateKey(i)
key := testchain.PrivateKeyByID(i)
return &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()}
}
@ -241,9 +241,8 @@ func signTx(t *testing.T, feePerByte util.Fixed8, txs ...*transaction.Transactio
validators := make([]*keys.PublicKey, 4)
privNetKeys := make([]*keys.PrivateKey, 4)
for i := 0; i < 4; i++ {
privateKey, publicKey := getTestValidator(i)
validators[i] = publicKey.PublicKey
privNetKeys[i] = privateKey.PrivateKey
privNetKeys[i] = testchain.PrivateKey(i)
validators[i] = privNetKeys[i].PublicKey()
}
rawScript, err := smartcontract.CreateMultiSigRedeemScript(3, validators)
require.NoError(t, err)

View file

@ -54,7 +54,7 @@ var (
ErrInvalidBlockIndex error = errors.New("invalid block index")
)
var (
genAmount = []int{8, 7, 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
genAmount = []int{6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
decrementInterval = 2000000
persistInterval = 1 * time.Second
)
@ -117,6 +117,8 @@ type Blockchain struct {
// cache for block verification keys.
keyCache map[util.Uint160]map[string]*keys.PublicKey
sbValidators keys.PublicKeys
log *zap.Logger
lastBatch *storage.MemBatch
@ -152,6 +154,10 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
cfg.MemPoolSize = defaultMemPoolSize
log.Info("mempool size is not set or wrong, setting default value", zap.Int("MemPoolSize", cfg.MemPoolSize))
}
validators, err := validatorsFromConfig(cfg)
if err != nil {
return nil, err
}
bc := &Blockchain{
config: cfg,
dao: dao.NewSimple(s, cfg.Magic),
@ -161,6 +167,7 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
runToExitCh: make(chan struct{}),
memPool: mempool.NewMemPool(cfg.MemPoolSize),
keyCache: make(map[util.Uint160]map[string]*keys.PublicKey),
sbValidators: validators,
log: log,
events: make(chan bcEvent),
subCh: make(chan interface{}),
@ -1235,8 +1242,10 @@ func (bc *Blockchain) PoolTx(t *transaction.Transaction) error {
}
//GetStandByValidators returns validators from the configuration.
func (bc *Blockchain) GetStandByValidators() (keys.PublicKeys, error) {
return getValidators(bc.config)
func (bc *Blockchain) GetStandByValidators() keys.PublicKeys {
res := make(keys.PublicKeys, len(bc.sbValidators))
copy(res, bc.sbValidators)
return res
}
// GetValidators returns next block validators.

View file

@ -37,7 +37,7 @@ type Blockchainer interface {
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog
GetNEP5Balances(util.Uint160) *state.NEP5Balances
GetValidators() ([]*keys.PublicKey, error)
GetStandByValidators() (keys.PublicKeys, error)
GetStandByValidators() keys.PublicKeys
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
GetStorageItem(id int32, key []byte) *state.StorageItem
GetStorageItems(id int32) (map[string]*state.StorageItem, error)

View file

@ -32,7 +32,7 @@ type DAO interface {
GetHeaderHashes() ([]util.Uint256, error)
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
GetNextContractID() (int32, error)
GetAndUpdateNextContractID() (int32, error)
GetStorageItem(id int32, key []byte) *state.StorageItem
GetStorageItems(id int32) (map[string]*state.StorageItem, error)
GetStorageItemsWithPrefix(id int32, prefix []byte) (map[string]*state.StorageItem, error)
@ -47,7 +47,6 @@ type DAO interface {
PutCurrentHeader(hashAndIndex []byte) error
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
PutNextContractID(id int32) error
PutStorageItem(id int32, key []byte, si *state.StorageItem) error
PutVersion(v string) error
StoreAsBlock(block *block.Block) error
@ -173,25 +172,19 @@ func (dao *Simple) DeleteContractState(hash util.Uint160) error {
return dao.Store.Delete(key)
}
// GetNextContractID returns id for the next contract and increases stored id.
func (dao *Simple) GetNextContractID() (int32, error) {
// GetAndUpdateNextContractID returns id for the next contract and increases stored ID.
func (dao *Simple) GetAndUpdateNextContractID() (int32, error) {
var id int32
key := storage.SYSContractID.Bytes()
data, err := dao.Store.Get(key)
if err != nil {
if err == storage.ErrKeyNotFound {
err = nil
}
if err == nil {
id = int32(binary.LittleEndian.Uint32(data))
} else if err != storage.ErrKeyNotFound {
return 0, err
}
return int32(binary.LittleEndian.Uint32(data)), nil
}
// PutNextContractID sets next contract id to id.
func (dao *Simple) PutNextContractID(id int32) error {
key := storage.SYSContractID.Bytes()
data := make([]byte, 4)
binary.LittleEndian.PutUint32(data, uint32(id))
return dao.Store.Put(key, data)
data = make([]byte, 4)
binary.LittleEndian.PutUint32(data, uint32(id+1))
return id, dao.Store.Put(key, data)
}
// -- end contracts.

View file

@ -84,15 +84,17 @@ func TestDeleteContractState(t *testing.T) {
require.Nil(t, gotContractState)
}
func TestSimple_GetNextContractID(t *testing.T) {
func TestSimple_GetAndUpdateNextContractID(t *testing.T) {
dao := NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet)
id, err := dao.GetNextContractID()
id, err := dao.GetAndUpdateNextContractID()
require.NoError(t, err)
require.EqualValues(t, 0, id)
require.NoError(t, dao.PutNextContractID(10))
id, err = dao.GetNextContractID()
id, err = dao.GetAndUpdateNextContractID()
require.NoError(t, err)
require.EqualValues(t, 10, id)
require.EqualValues(t, 1, id)
id, err = dao.GetAndUpdateNextContractID()
require.NoError(t, err)
require.EqualValues(t, 2, id)
}
func TestPutGetAppExecResult(t *testing.T) {

View file

@ -48,7 +48,7 @@ func (bc *Blockchain) newBlock(txs ...*transaction.Transaction) *block.Block {
}
func newBlock(cfg config.ProtocolConfiguration, index uint32, prev util.Uint256, txs ...*transaction.Transaction) *block.Block {
validators, _ := getValidators(cfg)
validators, _ := validatorsFromConfig(cfg)
vlen := len(validators)
valScript, _ := smartcontract.CreateMultiSigRedeemScript(
vlen-(vlen-1)/3,
@ -210,7 +210,7 @@ func TestCreateBasicChain(t *testing.T) {
t.Logf("txMoveNeo: %s", txMoveNeo.Hash().StringLE())
t.Logf("txMoveGas: %s", txMoveGas.Hash().StringLE())
require.Equal(t, util.Fixed8FromInt64(1000), bc.GetUtilityTokenBalance(priv0ScriptHash))
require.True(t, util.Fixed8FromInt64(1000).CompareTo(bc.GetUtilityTokenBalance(priv0ScriptHash)) <= 0)
// info for getblockheader rpc tests
t.Logf("header hash: %s", b.Hash().StringLE())
buf := io.NewBufBinWriter()
@ -399,10 +399,7 @@ func addCosigners(txs ...*transaction.Transaction) {
}
func signTx(bc *Blockchain, txs ...*transaction.Transaction) error {
validators, err := getValidators(bc.config)
if err != nil {
return errors.Wrap(err, "fail to sign tx")
}
validators := bc.GetStandByValidators()
rawScript, err := smartcontract.CreateMultiSigRedeemScript(len(bc.config.StandbyValidators)/2+1, validators)
if err != nil {
return errors.Wrap(err, "fail to sign tx")

View file

@ -91,14 +91,11 @@ func contractCreate(ic *interop.Context, v *vm.VM) error {
if contract != nil {
return errors.New("contract already exists")
}
id, err := ic.DAO.GetNextContractID()
id, err := ic.DAO.GetAndUpdateNextContractID()
if err != nil {
return err
}
newcontract.ID = id
if err := ic.DAO.PutNextContractID(id); err != nil {
return err
}
if err := ic.DAO.PutContractState(newcontract); err != nil {
return err
}

View file

@ -289,7 +289,7 @@ func storageGet(ic *interop.Context, v *vm.VM) error {
if si != nil && si.Value != nil {
v.Estack().PushVal(si.Value)
} else {
v.Estack().PushVal([]byte{})
v.Estack().PushVal(stackitem.Null{})
}
return nil
}

View file

@ -58,7 +58,11 @@ func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.Stor
return errors.New("insufficient funds")
}
acc.Balance.Add(&acc.Balance, amount)
if acc.Balance.Sign() != 0 {
si.Value = acc.Bytes()
} else {
si.Value = nil
}
return nil
}
@ -87,7 +91,7 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
absAmount := big.NewInt(int64(tx.SystemFee + tx.NetworkFee))
g.burn(ic, tx.Sender, absAmount)
}
validators, err := g.NEO.GetValidatorsInternal(ic.Chain, ic.DAO)
validators, err := g.NEO.GetNextBlockValidatorsInternal(ic.Chain, ic.DAO)
if err != nil {
return fmt.Errorf("cannot get block validators: %v", err)
}
@ -101,10 +105,7 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
}
func getStandbyValidatorsHash(ic *interop.Context) (util.Uint160, []*keys.PublicKey, error) {
vs, err := ic.Chain.GetStandByValidators()
if err != nil {
return util.Uint160{}, nil, err
}
vs := ic.Chain.GetStandByValidators()
s, err := smartcontract.CreateMultiSigRedeemScript(len(vs)/2+1, vs)
if err != nil {
return util.Uint160{}, nil, err

View file

@ -11,6 +11,7 @@ import (
"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/crypto/keys"
"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"
@ -112,8 +113,6 @@ func NewNEO() *NEO {
// Initialize initializes NEO contract.
func (n *NEO) Initialize(ic *interop.Context) error {
var si state.StorageItem
if err := n.nep5TokenNative.Initialize(ic); err != nil {
return err
}
@ -122,11 +121,6 @@ func (n *NEO) Initialize(ic *interop.Context) error {
return errors.New("already initialized")
}
vc := new(ValidatorsCount)
si.Value = vc.Bytes()
if err := ic.DAO.PutStorageItem(n.ContractID, validatorsCountKey, &si); err != nil {
return err
}
h, vs, err := getStandbyValidatorsHash(ic)
if err != nil {
return err
@ -165,10 +159,11 @@ func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.Sto
return err
}
if amount.Sign() == 0 {
si.Value = acc.Bytes()
return nil
}
if len(acc.Votes) > 0 {
if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance)); err != nil {
if err := n.ModifyAccountVotes(acc, ic.DAO, amount); err != nil {
return err
}
siVC := ic.DAO.GetStorageItem(n.ContractID, validatorsCountKey)
@ -186,7 +181,11 @@ func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.Sto
}
}
acc.Balance.Add(&acc.Balance, amount)
if acc.Balance.Sign() != 0 {
si.Value = acc.Bytes()
} else {
si.Value = nil
}
return nil
}
@ -225,10 +224,8 @@ func (n *NEO) registerValidatorInternal(ic *interop.Context, pub *keys.PublicKey
return errors.New("already registered")
}
si = new(state.StorageItem)
// It's the same simple counter, calling it `Votes` instead of `Balance`
// doesn't help a lot.
votes := state.NEP5BalanceState{}
si.Value = votes.Bytes()
// Zero value.
si.Value = []byte{}
return ic.DAO.PutStorageItem(n.ContractID, key, si)
}
@ -284,14 +281,21 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
newPubs = append(newPubs, pub)
}
if lp, lv := len(newPubs), len(acc.Votes); lp != lv {
si := ic.DAO.GetStorageItem(n.ContractID, validatorsCountKey)
var si *state.StorageItem
var vc *ValidatorsCount
var err error
si = ic.DAO.GetStorageItem(n.ContractID, validatorsCountKey)
if si == nil {
return errors.New("validators count uninitialized")
}
vc, err := ValidatorsCountFromBytes(si.Value)
// The first voter.
si = new(state.StorageItem)
vc = new(ValidatorsCount)
} else {
vc, err = ValidatorsCountFromBytes(si.Value)
if err != nil {
return err
}
}
if lv > 0 {
vc[lv-1].Sub(&vc[lv-1], &acc.Balance)
}
@ -319,12 +323,9 @@ func (n *NEO) ModifyAccountVotes(acc *state.NEOBalanceState, d dao.DAO, value *b
if si == nil {
return errors.New("invalid validator")
}
votes, err := state.NEP5BalanceStateFromBytes(si.Value)
if err != nil {
return err
}
votes.Balance.Add(&votes.Balance, value)
si.Value = votes.Bytes()
votes := bigint.FromBytes(si.Value)
votes.Add(votes, value)
si.Value = bigint.ToPreallocatedBytes(votes, si.Value[:0])
if err := d.PutStorageItem(n.ContractID, key, si); err != nil {
return err
}
@ -339,11 +340,8 @@ func (n *NEO) getRegisteredValidators(d dao.DAO) ([]keyWithVotes, error) {
}
arr := make([]keyWithVotes, 0, len(siMap))
for key, si := range siMap {
votes, err := state.NEP5BalanceStateFromBytes(si.Value)
if err != nil {
return nil, err
}
arr = append(arr, keyWithVotes{key, &votes.Balance})
votes := bigint.FromBytes(si.Value)
arr = append(arr, keyWithVotes{key, votes})
}
sort.Slice(arr, func(i, j int) bool { return strings.Compare(arr[i].Key, arr[j].Key) == -1 })
return arr, nil
@ -384,9 +382,10 @@ func (n *NEO) getRegisteredValidatorsCall(ic *interop.Context, _ []stackitem.Ite
// GetValidatorsInternal returns a list of current validators.
func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
standByValidators := bc.GetStandByValidators()
si := d.GetStorageItem(n.ContractID, validatorsCountKey)
if si == nil {
return nil, errors.New("validators count uninitialized")
return standByValidators, nil
}
validatorsCount, err := ValidatorsCountFromBytes(si.Value)
if err != nil {
@ -407,10 +406,6 @@ func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (ke
})
count := validatorsCount.GetWeightedAverage()
standByValidators, err := bc.GetStandByValidators()
if err != nil {
return nil, err
}
if count < len(standByValidators) {
count = len(standByValidators)
}

View file

@ -148,6 +148,28 @@ func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint1
ic.Notifications = append(ic.Notifications, ne)
}
func (c *nep5TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160, amount *big.Int) error {
key := makeAccountKey(acc)
si := ic.DAO.GetStorageItem(c.ContractID, key)
if si == nil {
if amount.Sign() <= 0 {
return errors.New("insufficient funds")
}
si = new(state.StorageItem)
}
err := c.incBalance(ic, acc, si, amount)
if err != nil {
return err
}
if si.Value == nil {
err = ic.DAO.DeleteStorageItem(c.ContractID, key)
} else {
err = ic.DAO.PutStorageItem(c.ContractID, key, si)
}
return err
}
func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, amount *big.Int) error {
if amount.Sign() == -1 {
return errors.New("negative amount")
@ -164,12 +186,6 @@ func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, a
return errors.New("invalid signature")
}
keyFrom := makeAccountKey(from)
siFrom := ic.DAO.GetStorageItem(c.ContractID, keyFrom)
if siFrom == nil {
return errors.New("insufficient funds")
}
isEmpty := from.Equals(to) || amount.Sign() == 0
inc := amount
if isEmpty {
@ -177,23 +193,12 @@ func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, a
} else {
inc = new(big.Int).Neg(inc)
}
if err := c.incBalance(ic, from, siFrom, inc); err != nil {
return err
}
if err := ic.DAO.PutStorageItem(c.ContractID, keyFrom, siFrom); err != nil {
if err := c.updateAccBalance(ic, from, inc); err != nil {
return err
}
if !isEmpty {
keyTo := makeAccountKey(to)
siTo := ic.DAO.GetStorageItem(c.ContractID, keyTo)
if siTo == nil {
siTo = new(state.StorageItem)
}
if err := c.incBalance(ic, to, siTo, amount); err != nil {
return err
}
if err := ic.DAO.PutStorageItem(c.ContractID, keyTo, siTo); err != nil {
if err := c.updateAccBalance(ic, to, amount); err != nil {
return err
}
}

View file

@ -104,28 +104,20 @@ func (s *NEOBalanceState) DecodeBinary(r *io.BinReader) {
if r.Err != nil {
return
}
s.fromStackItem(si)
r.Err = 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))
result.Append(stackitem.NewByteArray(s.Votes.Bytes()))
return result
}
func (s *NEOBalanceState) fromStackItem(item stackitem.Item) {
func (s *NEOBalanceState) fromStackItem(item stackitem.Item) error {
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] = new(keys.PublicKey)
s.Votes[i].DecodeBytes(v.Value().([]byte))
}
s.Votes = make(keys.PublicKeys, 0)
return s.Votes.DecodeBytes(structItem[2].Value().([]byte))
}

View file

@ -284,7 +284,7 @@ func (t *Transaction) FeePerByte() util.Fixed8 {
// transactionJSON is a wrapper for Transaction and
// used for correct marhalling of transaction.Data
type transactionJSON struct {
TxID util.Uint256 `json:"txid"`
TxID util.Uint256 `json:"hash"`
Size int `json:"size"`
Version uint8 `json:"version"`
Nonce uint32 `json:"nonce"`

View file

@ -34,7 +34,7 @@ var (
// createGenesisBlock creates a genesis block based on the given configuration.
func createGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error) {
validators, err := getValidators(cfg)
validators, err := validatorsFromConfig(cfg)
if err != nil {
return nil, err
}
@ -91,7 +91,7 @@ func deployNativeContracts(magic netmode.Magic) *transaction.Transaction {
return tx
}
func getValidators(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
func validatorsFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
validators := make([]*keys.PublicKey, len(cfg.StandbyValidators))
for i, pubKeyStr := range cfg.StandbyValidators {
pubKey, err := keys.NewPublicKeyFromString(pubKeyStr)

View file

@ -34,7 +34,7 @@ func TestGetConsensusAddressMainNet(t *testing.T) {
cfg, err := config.Load("../../config", netmode.MainNet)
require.NoError(t, err)
validators, err := getValidators(cfg.ProtocolConfiguration)
validators, err := validatorsFromConfig(cfg.ProtocolConfiguration)
require.NoError(t, err)
script, err := getNextConsensusAddress(validators)

View file

@ -38,9 +38,9 @@ func GetReadOnlyContext() Context { return Context{} }
func Put(ctx Context, key interface{}, value interface{}) {}
// Get retrieves value stored for the given key using given Context. See Put
// documentation on possible key and value types. This function uses
// `System.Storage.Get` syscall.
func Get(ctx Context, key interface{}) interface{} { return 0 }
// documentation on possible key and value types. If the value is not present in
// the database it returns nil. This function uses `System.Storage.Get` syscall.
func Get(ctx Context, key interface{}) interface{} { return nil }
// Delete removes key-value pair from storage by the given key using given
// Context. See Put documentation on possible key types. This function uses

View file

@ -85,7 +85,7 @@ func (chain testChain) GetNEP5Balances(util.Uint160) *state.NEP5Balances {
func (chain testChain) GetValidators() ([]*keys.PublicKey, error) {
panic("TODO")
}
func (chain testChain) GetStandByValidators() (keys.PublicKeys, error) {
func (chain testChain) GetStandByValidators() keys.PublicKeys {
panic("TODO")
}
func (chain testChain) GetEnrollments() ([]state.Validator, error) {

View file

@ -41,13 +41,13 @@ const hexB1 = "000000008aaab19c43c4ca2870c3e616b123f1b689866f44b138ae4d6a5352e54
const hexTxMoveNeo = "0002000000abec5362f11e75b6e02e407bb98d63675d14384100000000000000003e5f0d0000000000b00400000001abec5362f11e75b6e02e407bb98d63675d14384101590218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801fd08010c40ae6fc04fe4b6c22218ca9617c98d607d9ec9b1faf8cfdc3391bec485ae76b11adc6cc6abeb31a50b536ea8073e674d62a5566fce5e0a0ceb0718cb971c1ae3d00c40603071b725a58d052cad7afd88e99b27baab931afd5bb50d16e224335aab450170aabe251d3c0c6ad3f31dd7e9b89b209baabe5a1e2fa588bd8118f9e2a6960f0c40d72afcf39e663dba2d70fb8c36a09d1a6a6ad0d2fd38c857a8e7dc71e2b98711324e0d2ec641fe6896ba63ba80d3ea341c1aad11e082fb188ee07e215b4031b10c409afb2808b60286a56343b7ffcef28bb2ab0c595603e7323b5e5b0b9c1c10edfa5c40754d921865cb6fd71668a206b37a1eb10c0029a9fcd3a856aed07742cd3f94130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"
const b1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"size":1681,"nextblockhash":"0x45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d","confirmations":6,"hash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","version":0,"previousblockhash":"0x56fd4244e552536a4dae38b1446f8689b6f123b116e6c37028cac4439cb1aa8a","merkleroot":"0xf9dce467385206ad220a8b85d238f77239766eaffffed19955e3e47d24071140","time":1592472500001,"index":1,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEAPAetjcaE1Un3bIFoNrh9p0tMkg3zOEovq2QMwkYg/nOIebXWaQPaQdGWSsCHTl/CI47e0F/zvc80b/cKAB2lSDECE965dn1igmqVu6y8oJ0SlmoLRfjvg6xx/VObo33liDiYIGRusVygKg22y7Cp3bQfkPxa8dsR9NIsPzQnVbHwyDEArlbTjnsNRYqZAeV/yI+kt7JU5CgcutFf2pDIwUvgHMVF+DfAp5KRXIE93f1JhxqSojUbUw6vexjWm7tWA1sd/DEC5c1dFsd15WiWMMdjm+ofVz8Lps6SJDWENM7z4M7ZMWLDFzqF/OnEo8QZe0ZPmNpcVkPGT8ovdHu67vB/m587l","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"consensus_data":{"primary":0,"nonce":"0000000000000457"},"tx":[{"txid":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"0.0087635","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","scripts":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]},{"txid":"0xb661d5e4d9e41c3059b068f8abb6f1566a47ec800879e34c0ebd2799781a2760","size":579,"version":0,"nonce":3,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"0.0088035","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"AwDodkgXAAAADBQxboUQOQGdOd/Cw31sP+4Z/VgJhwwUq+xTYvEedbbgLkB7uY1jZ10UOEETwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I4","scripts":[{"invocation":"DECHEOe12Kxs2NCdb7Nb8tzOX1+zhZXdttBKVwvJJbwsVac83188taH+sKzE8myLvKbEPfO0qYuMPCyAnC8JbrJaDEDBhsECy/cjE/2U31B3/Fu+/NMiJ+0hWaR6RllId/o58zDYIjtFqiSv8AW+u1skJ6UMjE3oYY59ewDXPYNsRJQuDECiQ7W1Zb1LwvC7ES92JPazUUwSQTxalSMIGfrOP3YPA/y5axiPmAOKPyUWhrU6iNaXRPTkqYXmKXADqAzbFp6ADEBKlR5hrJnV7jGDHREXVK23EbSpBgqVJP44OpB3GEPNsJY4JnQCeofyoVqDvXfesrKrH+iz3m5UYpPvPfmxEp4o","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}]}}`
const b1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"size":1681,"nextblockhash":"0x45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d","confirmations":6,"hash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","version":0,"previousblockhash":"0x56fd4244e552536a4dae38b1446f8689b6f123b116e6c37028cac4439cb1aa8a","merkleroot":"0xf9dce467385206ad220a8b85d238f77239766eaffffed19955e3e47d24071140","time":1592472500001,"index":1,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEAPAetjcaE1Un3bIFoNrh9p0tMkg3zOEovq2QMwkYg/nOIebXWaQPaQdGWSsCHTl/CI47e0F/zvc80b/cKAB2lSDECE965dn1igmqVu6y8oJ0SlmoLRfjvg6xx/VObo33liDiYIGRusVygKg22y7Cp3bQfkPxa8dsR9NIsPzQnVbHwyDEArlbTjnsNRYqZAeV/yI+kt7JU5CgcutFf2pDIwUvgHMVF+DfAp5KRXIE93f1JhxqSojUbUw6vexjWm7tWA1sd/DEC5c1dFsd15WiWMMdjm+ofVz8Lps6SJDWENM7z4M7ZMWLDFzqF/OnEo8QZe0ZPmNpcVkPGT8ovdHu67vB/m587l","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"consensus_data":{"primary":0,"nonce":"0000000000000457"},"tx":[{"hash":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"0.0087635","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","scripts":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]},{"hash":"0xb661d5e4d9e41c3059b068f8abb6f1566a47ec800879e34c0ebd2799781a2760","size":579,"version":0,"nonce":3,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"0.0088035","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"AwDodkgXAAAADBQxboUQOQGdOd/Cw31sP+4Z/VgJhwwUq+xTYvEedbbgLkB7uY1jZ10UOEETwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I4","scripts":[{"invocation":"DECHEOe12Kxs2NCdb7Nb8tzOX1+zhZXdttBKVwvJJbwsVac83188taH+sKzE8myLvKbEPfO0qYuMPCyAnC8JbrJaDEDBhsECy/cjE/2U31B3/Fu+/NMiJ+0hWaR6RllId/o58zDYIjtFqiSv8AW+u1skJ6UMjE3oYY59ewDXPYNsRJQuDECiQ7W1Zb1LwvC7ES92JPazUUwSQTxalSMIGfrOP3YPA/y5axiPmAOKPyUWhrU6iNaXRPTkqYXmKXADqAzbFp6ADEBKlR5hrJnV7jGDHREXVK23EbSpBgqVJP44OpB3GEPNsJY4JnQCeofyoVqDvXfesrKrH+iz3m5UYpPvPfmxEp4o","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}]}}`
const hexHeader1 = "000000008aaab19c43c4ca2870c3e616b123f1b689866f44b138ae4d6a5352e54442fd56401107247de4e35599d1feffaf6e763972f738d2858b0a22ad06523867e4dcf921f7c1c67201000001000000abec5362f11e75b6e02e407bb98d63675d14384101fd08010c400f01eb6371a135527ddb205a0dae1f69d2d324837cce128bead9033091883f9ce21e6d759a40f690746592b021d397f088e3b7b417fcef73cd1bfdc2800769520c4084f7ae5d9f58a09aa56eeb2f282744a59a82d17e3be0eb1c7f54e6e8df79620e2608191bac57280a836db2ec2a776d07e43f16bc76c47d348b0fcd09d56c7c320c402b95b4e39ec35162a640795ff223e92dec95390a072eb457f6a4323052f80731517e0df029e4a457204f777f5261c6a4a88d46d4c3abdec635a6eed580d6c77f0c40b9735745b1dd795a258c31d8e6fa87d5cfc2e9b3a4890d610d33bcf833b64c58b0c5cea17f3a7128f1065ed193e636971590f193f28bdd1eeebbbc1fe6e7cee594130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb00"
const header1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"hash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","size":518,"version":0,"previousblockhash":"0x56fd4244e552536a4dae38b1446f8689b6f123b116e6c37028cac4439cb1aa8a","merkleroot":"0xf9dce467385206ad220a8b85d238f77239766eaffffed19955e3e47d24071140","time":1592472500001,"index":1,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEAPAetjcaE1Un3bIFoNrh9p0tMkg3zOEovq2QMwkYg/nOIebXWaQPaQdGWSsCHTl/CI47e0F/zvc80b/cKAB2lSDECE965dn1igmqVu6y8oJ0SlmoLRfjvg6xx/VObo33liDiYIGRusVygKg22y7Cp3bQfkPxa8dsR9NIsPzQnVbHwyDEArlbTjnsNRYqZAeV/yI+kt7JU5CgcutFf2pDIwUvgHMVF+DfAp5KRXIE93f1JhxqSojUbUw6vexjWm7tWA1sd/DEC5c1dFsd15WiWMMdjm+ofVz8Lps6SJDWENM7z4M7ZMWLDFzqF/OnEo8QZe0ZPmNpcVkPGT8ovdHu67vB/m587l","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"confirmations":6,"nextblockhash":"0x45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d"}}`
const txMoveNeoVerbose = `{"id":5,"jsonrpc":"2.0","result":{"blockhash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","confirmations":6,"blocktime":1592472500001,"txid":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"0.0087635","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","scripts":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}}`
const txMoveNeoVerbose = `{"id":5,"jsonrpc":"2.0","result":{"blockhash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","confirmations":6,"blocktime":1592472500001,"hash":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"0.0087635","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","scripts":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}}`
// getResultBlock1 returns data for block number 1 which is used by several tests.
func getResultBlock1() *result.Block {

View file

@ -119,7 +119,7 @@ func TestWSClientEvents(t *testing.T) {
`{"jsonrpc":"2.0","method":"transaction_executed","params":[{"txid":"0xe1cd5e57e721d2a2e05fb1f08721b12057b25ab1dd7fd0f33ee1639932fdfad7","trigger":"Application","vmstate":"HALT","gas_consumed":"2.291","stack":[],"notifications":[{"contract":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","state":{"type":"Array","value":[{"type":"ByteArray","value":"Y29udHJhY3QgY2FsbA=="},{"type":"ByteArray","value":"dHJhbnNmZXI="},{"type":"Array","value":[{"type":"ByteArray","value":"dpFiJB7t+XwkgWUq3xug9b9XQxs="},{"type":"ByteArray","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"Integer","value":"1000"}]}]}},{"contract":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","state":{"type":"Array","value":[{"type":"ByteArray","value":"dHJhbnNmZXI="},{"type":"ByteArray","value":"dpFiJB7t+XwkgWUq3xug9b9XQxs="},{"type":"ByteArray","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"Integer","value":"1000"}]}}]}]}`,
`{"jsonrpc":"2.0","method":"notification_from_execution","params":[{"contract":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","state":{"type":"Array","value":[{"type":"ByteArray","value":"Y29udHJhY3QgY2FsbA=="},{"type":"ByteArray","value":"dHJhbnNmZXI="},{"type":"Array","value":[{"type":"ByteArray","value":"dpFiJB7t+XwkgWUq3xug9b9XQxs="},{"type":"ByteArray","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"Integer","value":"1000"}]}]}}]}`,
`{"jsonrpc":"2.0","method":"transaction_executed","params":[{"txid":"0xf97a72b7722c109f909a8bc16c22368c5023d85828b09b127b237aace33cf099","trigger":"Application","vmstate":"HALT","gas_consumed":"0.0604261","stack":[],"notifications":[{"contract":"0xe65ff7b3a02d207b584a5c27057d4e9862ef01da","state":{"type":"Array","value":[{"type":"ByteArray","value":"Y29udHJhY3QgY2FsbA=="},{"type":"ByteArray","value":"dHJhbnNmZXI="},{"type":"Array","value":[{"type":"ByteArray","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"ByteArray","value":"IHKCdK+vw29DoHHTKM+j5inZy7A="},{"type":"Integer","value":"123"}]}]}},{"contract":"0xe65ff7b3a02d207b584a5c27057d4e9862ef01da","state":{"type":"Array","value":[{"type":"ByteArray","value":"dHJhbnNmZXI="},{"type":"ByteArray","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"ByteArray","value":"IHKCdK+vw29DoHHTKM+j5inZy7A="},{"type":"Integer","value":"123"}]}}]}]}`,
`{"jsonrpc":"2.0","method":"block_added","params":[{"hash":"0x2d312f6379ead13cf62634c703091b750e7903728df2a3cf5bd96ce80b84a849","version":0,"previousblockhash":"0xb8237d34c156cac6be7b01578decf8ac8c99a62f0b6f774d622aad7be0fe189d","merkleroot":"0xf89169e89361692b71e671f13c088e84c5325015c413e8f89e7ba38efdb41287","time":1592472500006,"index":6,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEDblVguNGXWbUswDvBfVJzBt76BJyJ0Ga6siquyjioGn4Dbr6zy1IvcLl3xN5akcejRy9e+Mr1qvpe/gkLgtW4QDEDRwPISZagMFjE/plXTnZ/gEU0IbBAAe23U29zVWteUmzRsPxF/MdzXvdffR9W0edkj17AmkWpn+5rqzH9aCOpLDECEvjgxZaRoAHEDNzp1REllLcGzMwrwSjudtzfgRglQL3g1BKerDx6cGHH73medRVkL9QVm4KzSxlywVtvhwBMrDEBuPKvzg5TtakFW2jr/bfmy1bn2FiLARlOySwaGdKRV93ozA5lVEIAvHbBlJtT4/5H8jHjbncXXMrP3OUHqebZz","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"consensus_data":{"primary":0,"nonce":"0000000000000457"},"tx":[{"txid":"0xf97a72b7722c109f909a8bc16c22368c5023d85828b09b127b237aace33cf099","size":265,"version":0,"nonce":9,"sender":"NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN","sys_fee":"0","net_fee":"0.0036521","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x870958fd19ee3f6c7dc3c2df399d013910856e31","scopes":"CalledByEntry"}],"script":"AHsMFCBygnSvr8NvQ6Bx0yjPo+Yp2cuwDBQxboUQOQGdOd/Cw31sP+4Z/VgJhxPADAh0cmFuc2ZlcgwU2gHvYphOfQUnXEpYeyAtoLP3X+ZBYn1bUjg=","scripts":[{"invocation":"DECwklSj3liZOJbktRtkVdUCu8U2LQlrU6Dv8NtMgd0xXbk5lXjc2p68xv6xtJXbJ4aoFMJZ9lkcNpGoeUCcaCet","verification":"DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQQqQatQ="}]}]}]}`,
`{"jsonrpc":"2.0","method":"block_added","params":[{"hash":"0x2d312f6379ead13cf62634c703091b750e7903728df2a3cf5bd96ce80b84a849","version":0,"previousblockhash":"0xb8237d34c156cac6be7b01578decf8ac8c99a62f0b6f774d622aad7be0fe189d","merkleroot":"0xf89169e89361692b71e671f13c088e84c5325015c413e8f89e7ba38efdb41287","time":1592472500006,"index":6,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEDblVguNGXWbUswDvBfVJzBt76BJyJ0Ga6siquyjioGn4Dbr6zy1IvcLl3xN5akcejRy9e+Mr1qvpe/gkLgtW4QDEDRwPISZagMFjE/plXTnZ/gEU0IbBAAe23U29zVWteUmzRsPxF/MdzXvdffR9W0edkj17AmkWpn+5rqzH9aCOpLDECEvjgxZaRoAHEDNzp1REllLcGzMwrwSjudtzfgRglQL3g1BKerDx6cGHH73medRVkL9QVm4KzSxlywVtvhwBMrDEBuPKvzg5TtakFW2jr/bfmy1bn2FiLARlOySwaGdKRV93ozA5lVEIAvHbBlJtT4/5H8jHjbncXXMrP3OUHqebZz","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"consensus_data":{"primary":0,"nonce":"0000000000000457"},"tx":[{"hash":"0xf97a72b7722c109f909a8bc16c22368c5023d85828b09b127b237aace33cf099","size":265,"version":0,"nonce":9,"sender":"NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN","sys_fee":"0","net_fee":"0.0036521","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x870958fd19ee3f6c7dc3c2df399d013910856e31","scopes":"CalledByEntry"}],"script":"AHsMFCBygnSvr8NvQ6Bx0yjPo+Yp2cuwDBQxboUQOQGdOd/Cw31sP+4Z/VgJhxPADAh0cmFuc2ZlcgwU2gHvYphOfQUnXEpYeyAtoLP3X+ZBYn1bUjg=","scripts":[{"invocation":"DECwklSj3liZOJbktRtkVdUCu8U2LQlrU6Dv8NtMgd0xXbk5lXjc2p68xv6xtJXbJ4aoFMJZ9lkcNpGoeUCcaCet","verification":"DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQQqQatQ="}]}]}]}`,
`{"jsonrpc":"2.0","method":"event_missed","params":[]}`,
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {

View file

@ -50,8 +50,8 @@ type rpcTestCase struct {
check func(t *testing.T, e *executor, result interface{})
}
const testContractHash = "e65ff7b3a02d207b584a5c27057d4e9862ef01da"
const deploymentTxHash = "b0428600383ec7f7b06734978a24dbe81edc87b781f58c0614f122c735d8cf6a"
const testContractHash = "10e262ef80c76bdecca287a2c047841fc02c3129"
const deploymentTxHash = "ad8b149c799d4b2337162b0ad23e0ba8845cddb9cfca8a45587ee207015d2a7c"
var rpcTestCases = map[string][]rpcTestCase{
"getapplicationlog": {
@ -147,7 +147,7 @@ var rpcTestCases = map[string][]rpcTestCase{
},
{
Asset: e.chain.UtilityTokenHash(),
Amount: "923.96937740",
Amount: "918.01738700",
LastUpdated: 6,
}},
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
@ -229,7 +229,7 @@ var rpcTestCases = map[string][]rpcTestCase{
Timestamp: blockSendNEO.Timestamp,
Asset: e.chain.UtilityTokenHash(),
Address: "", // Minted GAS.
Amount: "23.99976000",
Amount: "17.99982000",
Index: 4,
NotifyIndex: 0,
TxHash: txSendNEOHash,
@ -259,6 +259,7 @@ var rpcTestCases = map[string][]rpcTestCase{
// take burned gas into account
u := testchain.PrivateKeyByID(0).GetScriptHash()
for i := 0; i <= int(e.chain.BlockHeight()); i++ {
var netFee util.Fixed8
h := e.chain.GetHeaderHash(i)
b, err := e.chain.GetBlock(h)
require.NoError(t, err)
@ -274,7 +275,19 @@ var rpcTestCases = map[string][]rpcTestCase{
TxHash: b.Hash(),
})
}
netFee += b.Transactions[j].NetworkFee
}
if i > 0 {
expected.Received = append(expected.Received, result.NEP5Transfer{
Timestamp: b.Timestamp,
Asset: e.chain.UtilityTokenHash(),
Address: "", // minted from network fees.
Amount: amountToString(int64(netFee), 8),
Index: b.Index,
TxHash: b.Hash(),
})
}
}
require.Equal(t, expected.Address, res.Address)
require.ElementsMatch(t, expected.Sent, res.Sent)
@ -552,8 +565,7 @@ var rpcTestCases = map[string][]rpcTestCase{
check: func(t *testing.T, e *executor, resp interface{}) {
s, ok := resp.(*string)
require.True(t, ok)
// Incorrect, to be fixed later.
assert.Equal(t, "48000", *s)
assert.Equal(t, "36000", *s)
},
},
},
@ -565,8 +577,7 @@ var rpcTestCases = map[string][]rpcTestCase{
},
check: func(t *testing.T, e *executor, validators interface{}) {
var expected []result.Validator
sBValidators, err := e.chain.GetStandByValidators()
require.NoError(t, err)
sBValidators := e.chain.GetStandByValidators()
for _, sbValidator := range sBValidators {
expected = append(expected, result.Validator{
PublicKey: *sbValidator,

Binary file not shown.

View file

@ -32,7 +32,11 @@ func Main(operation string, args []interface{}) interface{} {
runtime.Log("invalid address")
return false
}
amount := storage.Get(ctx, addr).(int)
var amount int
val := storage.Get(ctx, addr)
if val != nil {
amount = val.(int)
}
runtime.Notify("balanceOf", addr, amount)
return amount
case "transfer":
@ -53,7 +57,11 @@ func Main(operation string, args []interface{}) interface{} {
return false
}
fromBalance := storage.Get(ctx, from).(int)
var fromBalance int
val := storage.Get(ctx, from)
if val != nil {
fromBalance = val.(int)
}
if fromBalance < amount {
runtime.Log("insufficient funds")
return false
@ -61,7 +69,11 @@ func Main(operation string, args []interface{}) interface{} {
fromBalance -= amount
storage.Put(ctx, from, fromBalance)
toBalance := storage.Get(ctx, to).(int)
var toBalance int
val = storage.Get(ctx, to)
if val != nil {
toBalance = val.(int)
}
toBalance += amount
storage.Put(ctx, to, toBalance)

Binary file not shown.

View file

@ -212,7 +212,7 @@ func (p *Parameter) EncodeBinary(w *io.BinWriter) {
w.WriteBytes(p.Value.(util.Uint160).BytesBE())
case Hash256Type:
w.WriteBytes(p.Value.(util.Uint256).BytesBE())
case InteropInterfaceType:
case InteropInterfaceType, AnyType:
default:
w.Err = fmt.Errorf("unknown type: %x", p.Type)
}
@ -251,7 +251,7 @@ func (p *Parameter) DecodeBinary(r *io.BinReader) {
var u util.Uint256
r.ReadBytes(u[:])
p.Value = u
case InteropInterfaceType:
case InteropInterfaceType, AnyType:
default:
r.Err = fmt.Errorf("unknown type: %x", p.Type)
}

View file

@ -41,6 +41,9 @@ type Context struct {
// Script hash of the prog.
scriptHash util.Uint160
// Caller's contract script hash.
callingScriptHash util.Uint160
// Call flags this context was created with.
callFlag smartcontract.CallFlag
}

View file

@ -276,9 +276,11 @@ func (v *VM) LoadScriptWithFlags(b []byte, f smartcontract.CallFlag) {
// given script hash directly into the Context to avoid its recalculations. It's
// up to user of this function to make sure the script and hash match each other.
func (v *VM) LoadScriptWithHash(b []byte, hash util.Uint160, f smartcontract.CallFlag) {
shash := v.GetCurrentScriptHash()
v.LoadScriptWithFlags(b, f)
ctx := v.Context()
ctx.scriptHash = hash
ctx.callingScriptHash = shash
}
// Context returns the current executed context. Nil if there is no context,
@ -1607,7 +1609,7 @@ func (v *VM) bytesToPublicKey(b []byte) *keys.PublicKey {
// GetCallingScriptHash implements ScriptHashGetter interface
func (v *VM) GetCallingScriptHash() util.Uint160 {
return v.getContextScriptHash(1)
return v.Context().callingScriptHash
}
// GetEntryScriptHash implements ScriptHashGetter interface