mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-27 13:58:05 +00:00
Merge pull request #1093 from nspcc-dev/fix-some-inconsistencies-wrt-sharp
Fix some inconsistencies wrt sharp
This commit is contained in:
commit
5d51ceaeac
32 changed files with 289 additions and 176 deletions
|
@ -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),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -659,8 +659,26 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
return nil
|
||||
}
|
||||
|
||||
ast.Walk(c, n.X)
|
||||
ast.Walk(c, n.Y)
|
||||
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:
|
||||
|
|
55
pkg/compiler/nilcheck_test.go
Normal file
55
pkg/compiler/nilcheck_test.go
Normal 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)
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
si.Value = acc.Bytes()
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
si.Value = acc.Bytes()
|
||||
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,13 +281,20 @@ 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)
|
||||
if err != nil {
|
||||
return err
|
||||
// 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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
Binary file not shown.
18
pkg/rpc/server/testdata/test_contract.go
vendored
18
pkg/rpc/server/testdata/test_contract.go
vendored
|
@ -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)
|
||||
|
||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue