emit: implement AppCallWithOperationAndArgs
It is nice to have a typical task of calling contract method with specific arguments incapsulated inside some function.
This commit is contained in:
parent
d4622768d1
commit
db2dccf7cb
4 changed files with 64 additions and 24 deletions
|
@ -318,12 +318,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
|
||||
// Now invoke this contract.
|
||||
script = io.NewBufBinWriter()
|
||||
emit.String(script.BinWriter, "testvalue")
|
||||
emit.String(script.BinWriter, "testkey")
|
||||
emit.Int(script.BinWriter, 2)
|
||||
emit.Opcode(script.BinWriter, opcode.PACK)
|
||||
emit.String(script.BinWriter, "Put")
|
||||
emit.AppCall(script.BinWriter, hash.Hash160(avm), false)
|
||||
emit.AppCallWithOperationAndArgs(script.BinWriter, hash.Hash160(avm), "Put", "testkey", "testvalue")
|
||||
|
||||
txInv := transaction.NewInvocationTX(script.Bytes(), 0)
|
||||
b = bc.newBlock(newMinerTX(), txInv)
|
||||
|
@ -355,10 +350,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
|
||||
sh := hash.Hash160(avm)
|
||||
w := io.NewBufBinWriter()
|
||||
emit.Int(w.BinWriter, 0)
|
||||
emit.Opcode(w.BinWriter, opcode.NEWARRAY)
|
||||
emit.String(w.BinWriter, "init")
|
||||
emit.AppCall(w.BinWriter, sh, true)
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, sh, "init")
|
||||
initTx := transaction.NewInvocationTX(w.Bytes(), 0)
|
||||
transferTx := newNEP5Transfer(sh, sh, priv0.GetScriptHash(), 1000)
|
||||
|
||||
|
@ -406,13 +398,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
|
||||
func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction {
|
||||
w := io.NewBufBinWriter()
|
||||
emit.Int(w.BinWriter, amount)
|
||||
emit.Bytes(w.BinWriter, to.BytesBE())
|
||||
emit.Bytes(w.BinWriter, from.BytesBE())
|
||||
emit.Int(w.BinWriter, 3)
|
||||
emit.Opcode(w.BinWriter, opcode.PACK)
|
||||
emit.String(w.BinWriter, "transfer")
|
||||
emit.AppCall(w.BinWriter, sc, false)
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount)
|
||||
emit.Opcode(w.BinWriter, opcode.THROWIFNOT)
|
||||
|
||||
script := w.Bytes()
|
||||
|
|
|
@ -104,13 +104,7 @@ func (c *Client) TransferNEP5(acc *wallet.Account, to util.Uint160, token *walle
|
|||
// Note: we don't use invoke function here because it requires
|
||||
// 2 round trips instead of one.
|
||||
w := io.NewBufBinWriter()
|
||||
emit.Int(w.BinWriter, amount)
|
||||
emit.Bytes(w.BinWriter, to.BytesBE())
|
||||
emit.Bytes(w.BinWriter, from.BytesBE())
|
||||
emit.Int(w.BinWriter, 3)
|
||||
emit.Opcode(w.BinWriter, opcode.PACK)
|
||||
emit.String(w.BinWriter, "transfer")
|
||||
emit.AppCall(w.BinWriter, token.Hash, false)
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, token.Hash, "transfer", from, to, amount)
|
||||
emit.Opcode(w.BinWriter, opcode.THROWIFNOT)
|
||||
|
||||
tx := transaction.NewInvocationTX(w.Bytes(), gas)
|
||||
|
|
|
@ -48,6 +48,29 @@ func Int(w *io.BinWriter, i int64) {
|
|||
}
|
||||
}
|
||||
|
||||
// Array emits array of elements to the given buffer.
|
||||
func Array(w *io.BinWriter, es ...interface{}) {
|
||||
for i := len(es) - 1; i >= 0; i-- {
|
||||
switch e := es[i].(type) {
|
||||
case int64:
|
||||
Int(w, e)
|
||||
case string:
|
||||
String(w, e)
|
||||
case util.Uint160:
|
||||
Bytes(w, e.BytesBE())
|
||||
case []byte:
|
||||
Bytes(w, e)
|
||||
case bool:
|
||||
Bool(w, e)
|
||||
default:
|
||||
w.Err = errors.New("unsupported type")
|
||||
return
|
||||
}
|
||||
}
|
||||
Int(w, int64(len(es)))
|
||||
Opcode(w, opcode.PACK)
|
||||
}
|
||||
|
||||
// String emits a string to the given buffer.
|
||||
func String(w *io.BinWriter, s string) {
|
||||
Bytes(w, []byte(s))
|
||||
|
@ -118,6 +141,13 @@ func AppCall(w *io.BinWriter, scriptHash util.Uint160, tailCall bool) {
|
|||
Instruction(w, op, scriptHash.BytesBE())
|
||||
}
|
||||
|
||||
// AppCallWithOperationAndArgs emits an APPCALL with the given operation and arguments.
|
||||
func AppCallWithOperationAndArgs(w *io.BinWriter, scriptHash util.Uint160, operation string, args ...interface{}) {
|
||||
Array(w, args...)
|
||||
String(w, operation)
|
||||
AppCall(w, scriptHash, false)
|
||||
}
|
||||
|
||||
// AppCallWithOperationAndData emits an appcall with the given operation and data.
|
||||
func AppCallWithOperationAndData(w *io.BinWriter, scriptHash util.Uint160, operation string, data []byte) {
|
||||
Bytes(w, data)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEmitInt(t *testing.T) {
|
||||
|
@ -107,6 +108,35 @@ func TestBytes(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestEmitArray(t *testing.T) {
|
||||
t.Run("good", func(t *testing.T) {
|
||||
buf := io.NewBufBinWriter()
|
||||
Array(buf.BinWriter, int64(1), "str", true, []byte{0xCA, 0xFE})
|
||||
require.NoError(t, buf.Err)
|
||||
|
||||
res := buf.Bytes()
|
||||
assert.EqualValues(t, opcode.PUSHBYTES2, res[0])
|
||||
assert.EqualValues(t, []byte{0xCA, 0xFE}, res[1:3])
|
||||
assert.EqualValues(t, opcode.PUSHT, res[3])
|
||||
assert.EqualValues(t, opcode.PUSHBYTES3, res[4])
|
||||
assert.EqualValues(t, []byte("str"), res[5:8])
|
||||
assert.EqualValues(t, opcode.PUSH1, res[8])
|
||||
})
|
||||
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
buf := io.NewBufBinWriter()
|
||||
Array(buf.BinWriter)
|
||||
require.NoError(t, buf.Err)
|
||||
assert.EqualValues(t, []byte{0, byte(opcode.PACK)}, buf.Bytes())
|
||||
})
|
||||
|
||||
t.Run("invalid type", func(t *testing.T) {
|
||||
buf := io.NewBufBinWriter()
|
||||
Array(buf.BinWriter, struct{}{})
|
||||
require.Error(t, buf.Err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEmitBool(t *testing.T) {
|
||||
buf := io.NewBufBinWriter()
|
||||
Bool(buf.BinWriter, true)
|
||||
|
|
Loading…
Reference in a new issue