Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: implement System.Blockchain.GetTransaction and System.Blockchain.GetBlock interops #1034

Merged
merged 7 commits into from
Jun 10, 2020
4 changes: 4 additions & 0 deletions pkg/compiler/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,10 @@ func (c *codegen) convertSyscall(expr *ast.CallExpr, api, name string) {
emit.Opcode(c.prog.BinWriter, opcode.PACK)
}
emit.Syscall(c.prog.BinWriter, api)
switch name {
case "GetTransaction", "GetBlock":
c.emitConvert(stackitem.StructT)
}

// This NOP instruction is basically not needed, but if we do, we have a
// one to one matching avm file with neo-python which is very nice for debugging.
Expand Down
31 changes: 9 additions & 22 deletions pkg/compiler/syscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ var syscalls = map[string]map[string]string{
"GetVotes": "Neo.Account.GetVotes",
"IsStandard": "Neo.Account.IsStandard",
},
"attribute": {
"GetUsage": "Neo.Attribute.GetUsage",
"GetData": "Neo.Attribute.GetData",
},
"crypto": {
"ECDsaVerify": "Neo.Crypto.ECDsaVerify",
},
Expand Down Expand Up @@ -39,14 +35,15 @@ var syscalls = map[string]map[string]string{
"Deserialize": "Neo.Runtime.Deserialize",
},
"blockchain": {
"GetAccount": "Neo.Blockchain.GetAccount",
"GetBlock": "Neo.Blockchain.GetBlock",
"GetContract": "Neo.Blockchain.GetContract",
"GetHeader": "Neo.Blockchain.GetHeader",
"GetHeight": "Neo.Blockchain.GetHeight",
"GetTransaction": "Neo.Blockchain.GetTransaction",
"GetTransactionHeight": "Neo.Blockchain.GetTransactionHeight",
"GetValidators": "Neo.Blockchain.GetValidators",
"GetAccount": "Neo.Blockchain.GetAccount",
"GetBlock": "System.Blockchain.GetBlock",
"GetContract": "Neo.Blockchain.GetContract",
"GetHeader": "Neo.Blockchain.GetHeader",
"GetHeight": "Neo.Blockchain.GetHeight",
"GetTransaction": "System.Blockchain.GetTransaction",
"GetTransactionFromBlock": "System.Blockchain.GetTransactionFromBlock",
"GetTransactionHeight": "System.Blockchain.GetTransactionHeight",
"GetValidators": "Neo.Blockchain.GetValidators",
},
"header": {
"GetIndex": "Neo.Header.GetIndex",
Expand All @@ -58,16 +55,6 @@ var syscalls = map[string]map[string]string{
"GetConsensusData": "Neo.Header.GetConsensusData",
"GetNextConsensus": "Neo.Header.GetNextConsensus",
},
"block": {
"GetTransactionCount": "Neo.Block.GetTransactionCount",
"GetTransactions": "Neo.Block.GetTransactions",
"GetTransaction": "Neo.Block.GetTransaction",
},
"transaction": {
"GetAttributes": "Neo.Transaction.GetAttributes",
"GetHash": "Neo.Transaction.GetHash",
"GetWitnesses": "Neo.Transaction.GetWitnesses",
},
"contract": {
"GetScript": "Neo.Contract.GetScript",
"IsPayable": "Neo.Contract.IsPayable",
Expand Down
17 changes: 7 additions & 10 deletions pkg/core/gas_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,19 @@ func getSyscallPrice(v *vm.VM, id uint32) util.Fixed8 {
}

const (
neoContractCreate = 0x6ea56cf6 // Neo.Contract.Create
neoContractMigrate = 0x90621b47 // Neo.Contract.Migrate
antSharesContractCreate = 0x2a28d29b // AntShares.Contract.Create
antSharesContractMigrate = 0xa934c8bb // AntShares.Contract.Migrate
systemStoragePut = 0x84183fe6 // System.Storage.Put
systemStoragePutEx = 0x3a9be173 // System.Storage.PutEx
neoStoragePut = 0xf541a152 // Neo.Storage.Put
antSharesStoragePut = 0x5f300a9e // AntShares.Storage.Put
neoContractCreate = 0x6ea56cf6 // Neo.Contract.Create
neoContractMigrate = 0x90621b47 // Neo.Contract.Migrate
systemStoragePut = 0x84183fe6 // System.Storage.Put
systemStoragePutEx = 0x3a9be173 // System.Storage.PutEx
neoStoragePut = 0xf541a152 // Neo.Storage.Put
)

estack := v.Estack()

switch id {
case neoContractCreate, neoContractMigrate, antSharesContractCreate, antSharesContractMigrate:
case neoContractCreate, neoContractMigrate:
return smartcontract.GetDeploymentPrice(smartcontract.PropertyState(estack.Peek(3).BigInt().Int64()))
case systemStoragePut, systemStoragePutEx, neoStoragePut, antSharesStoragePut:
case systemStoragePut, systemStoragePutEx, neoStoragePut:
// price for storage PUT is 1 GAS per 1 KiB
keySize := len(estack.Peek(1).Bytes())
valSize := len(estack.Peek(2).Bytes())
Expand Down
58 changes: 0 additions & 58 deletions pkg/core/interop_neo.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,42 +57,6 @@ func headerGetNextConsensus(ic *interop.Context, v *vm.VM) error {
return nil
}

// txGetAttributes returns current transaction attributes.
func txGetAttributes(ic *interop.Context, v *vm.VM) error {
txInterface := v.Estack().Pop().Value()
tx, ok := txInterface.(*transaction.Transaction)
if !ok {
return errors.New("value is not a transaction")
}
if len(tx.Attributes) > vm.MaxArraySize {
return errors.New("too many attributes")
}
attrs := make([]stackitem.Item, 0, len(tx.Attributes))
for i := range tx.Attributes {
attrs = append(attrs, stackitem.NewInterop(&tx.Attributes[i]))
}
v.Estack().PushVal(attrs)
return nil
}

// txGetWitnesses returns current transaction witnesses.
func txGetWitnesses(ic *interop.Context, v *vm.VM) error {
txInterface := v.Estack().Pop().Value()
tx, ok := txInterface.(*transaction.Transaction)
if !ok {
return errors.New("value is not a transaction")
}
if len(tx.Scripts) > vm.MaxArraySize {
return errors.New("too many outputs")
}
scripts := make([]stackitem.Item, 0, len(tx.Scripts))
for i := range tx.Scripts {
scripts = append(scripts, stackitem.NewInterop(&tx.Scripts[i]))
}
v.Estack().PushVal(scripts)
return nil
}

// witnessGetVerificationScript returns current witness' script.
func witnessGetVerificationScript(ic *interop.Context, v *vm.VM) error {
witInterface := v.Estack().Pop().Value()
Expand All @@ -107,28 +71,6 @@ func witnessGetVerificationScript(ic *interop.Context, v *vm.VM) error {
return nil
}

// attrGetData returns tx attribute data.
func attrGetData(ic *interop.Context, v *vm.VM) error {
attrInterface := v.Estack().Pop().Value()
attr, ok := attrInterface.(*transaction.Attribute)
if !ok {
return fmt.Errorf("%T is not an attribute", attr)
}
v.Estack().PushVal(attr.Data)
return nil
}

// attrGetData returns tx attribute usage field.
func attrGetUsage(ic *interop.Context, v *vm.VM) error {
attrInterface := v.Estack().Pop().Value()
attr, ok := attrInterface.(*transaction.Attribute)
if !ok {
return fmt.Errorf("%T is not an attribute", attr)
}
v.Estack().PushVal(int(attr.Usage))
return nil
}

// bcGetAccount returns or creates an account.
func bcGetAccount(ic *interop.Context, v *vm.VM) error {
accbytes := v.Estack().Pop().Bytes()
Expand Down
47 changes: 14 additions & 33 deletions pkg/core/interop_neo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,6 @@ func TestHeaderGetNextConsensus(t *testing.T) {
require.Equal(t, block.NextConsensus.BytesBE(), value)
}

func TestTxGetAttributes(t *testing.T) {
v, tx, context, chain := createVMAndPushTX(t)
defer chain.Close()

err := txGetAttributes(context, v)
require.NoError(t, err)
value := v.Estack().Pop().Value().([]stackitem.Item)
require.Equal(t, tx.Attributes[0].Usage, value[0].Value().(*transaction.Attribute).Usage)
}

func TestWitnessGetVerificationScript(t *testing.T) {
v := vm.New()
script := []byte{byte(opcode.PUSHM1), byte(opcode.RET)}
Expand Down Expand Up @@ -280,28 +270,6 @@ func TestECDSAVerify(t *testing.T) {
})
}

func TestAttrGetData(t *testing.T) {
v, tx, context, chain := createVMAndTX(t)
defer chain.Close()
v.Estack().PushVal(stackitem.NewInterop(&tx.Attributes[0]))

err := attrGetData(context, v)
require.NoError(t, err)
data := v.Estack().Pop().Value()
require.Equal(t, tx.Attributes[0].Data, data)
}

func TestAttrGetUsage(t *testing.T) {
v, tx, context, chain := createVMAndTX(t)
defer chain.Close()
v.Estack().PushVal(stackitem.NewInterop(&tx.Attributes[0]))

err := attrGetUsage(context, v)
require.NoError(t, err)
usage := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(tx.Attributes[0].Usage)), usage)
}

func TestAccountGetScriptHash(t *testing.T) {
v, accState, context, chain := createVMAndAccState(t)
defer chain.Close()
Expand Down Expand Up @@ -337,12 +305,25 @@ func TestContractIsPayable(t *testing.T) {

// Helper functions to create VM, InteropContext, TX, Account, Contract.

func createVM(t *testing.T) (*vm.VM, *interop.Context, *Blockchain) {
v := vm.New()
chain := newTestChain(t)
context := chain.newInteropContext(trigger.Application,
dao.NewSimple(storage.NewMemoryStore()), nil, nil)
return v, context, chain
}

func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
v, block, context, chain := createVMAndBlock(t)
v.Estack().PushVal(stackitem.NewInterop(block))
return v, block, context, chain
}

func createVMAndBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
v := vm.New()
block := newDumbBlock()
chain := newTestChain(t)
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), block, nil)
v.Estack().PushVal(stackitem.NewInterop(block))
return v, block, context, chain
}

Expand Down
Loading