Skip to content

Commit

Permalink
Merge pull request #64 from ElrondNetwork/agar-test
Browse files Browse the repository at this point in the history
Agar test
  • Loading branch information
sasurobert authored Feb 3, 2020
2 parents 3442ff3 + 3f00342 commit 61e706e
Show file tree
Hide file tree
Showing 91 changed files with 1,837 additions and 142 deletions.
26 changes: 5 additions & 21 deletions arwen/contexts/output.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package contexts

import (
"bytes"
"math/big"

"github.com/ElrondNetwork/arwen-wasm-vm/arwen"
Expand Down Expand Up @@ -152,27 +151,12 @@ func (context *outputContext) WriteLog(address []byte, topics [][]byte, data []b
return
}

var currentLogEntry *vmcommon.LogEntry
currentLogEntry = nil

for _, logEntry := range context.outputState.Logs {
if bytes.Equal(logEntry.Address, address) {
currentLogEntry = logEntry
break
}
}

if currentLogEntry == nil {
currentLogEntry = &vmcommon.LogEntry{
Address: address,
Topics: make([][]byte, 0),
Data: make([]byte, 0),
}
context.outputState.Logs = append(context.outputState.Logs, currentLogEntry)
newLogEntry := &vmcommon.LogEntry{
Address: address,
Topics: topics,
Data: data,
}

currentLogEntry.Topics = append(currentLogEntry.Topics, topics...)
currentLogEntry.Data = append(currentLogEntry.Data, data...)
context.outputState.Logs = append(context.outputState.Logs, newLogEntry)
}

// Transfer handles any necessary value transfer required and takes
Expand Down
78 changes: 55 additions & 23 deletions arwen/elrondapi/elrondei.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ package elrondapi
// extern void getExternalBalance(void *context, int32_t addressOffset, int32_t resultOffset);
// extern int32_t blockHash(void *context, long long nonce, int32_t resultOffset);
// extern int32_t transferValue(void *context, long long gas, int32_t dstOffset, int32_t valueOffset, int32_t dataOffset, int32_t length);
// extern int32_t getArgumentLength(void *context, int32_t id);
// extern int32_t getArgument(void *context, int32_t id, int32_t argOffset);
// extern int32_t getFunction(void *context, int32_t functionOffset);
// extern int32_t getNumArguments(void *context);
// extern int32_t storageStore(void *context, int32_t keyOffset, int32_t dataOffset, int32_t dataLength);
// extern int32_t storageGetValueLength(void *context, int32_t keyOffset);
// extern int32_t storageLoad(void *context, int32_t keyOffset, int32_t dataOffset);
// extern void getCaller(void *context, int32_t resultOffset);
// extern int32_t callValue(void *context, int32_t resultOffset);
// extern void writeLog(void *context, int32_t pointer, int32_t length, int32_t topicPtr, int32_t numTopics);
// extern void returnData(void* context, int32_t dataOffset, int32_t length);
// extern void signalError(void* context);
// extern void signalExit(void* context, int32_t exitCode);
// extern void signalError(void* context, int32_t messageOffset, int32_t messageLength);
// extern long long getGasLeft(void *context);
//
// extern int32_t executeOnDestContext(void *context, long long gas, int32_t addressOffset, int32_t valueOffset, int32_t functionOffset, int32_t functionLength, int32_t numArguments, int32_t argumentsLengthOffset, int32_t dataOffset);
Expand Down Expand Up @@ -85,6 +86,11 @@ func ElrondEImports() (*wasmer.Imports, error) {
return nil, err
}

imports, err = imports.Append("getArgumentLength", getArgumentLength, C.getArgumentLength)
if err != nil {
return nil, err
}

imports, err = imports.Append("getArgument", getArgument, C.getArgument)
if err != nil {
return nil, err
Expand All @@ -105,6 +111,11 @@ func ElrondEImports() (*wasmer.Imports, error) {
return nil, err
}

imports, err = imports.Append("storageGetValueLength", storageGetValueLength, C.storageGetValueLength)
if err != nil {
return nil, err
}

imports, err = imports.Append("storageLoad", storageLoad, C.storageLoad)
if err != nil {
return nil, err
Expand Down Expand Up @@ -135,11 +146,6 @@ func ElrondEImports() (*wasmer.Imports, error) {
return nil, err
}

imports, err = imports.Append("signalExit", signalExit, C.signalExit)
if err != nil {
return nil, err
}

imports, err = imports.Append("getBlockTimestamp", getBlockTimestamp, C.getBlockTimestamp)
if err != nil {
return nil, err
Expand Down Expand Up @@ -289,25 +295,16 @@ func getOwner(context unsafe.Pointer, resultOffset int32) {
}

//export signalError
func signalError(context unsafe.Pointer) {
func signalError(context unsafe.Pointer, messageOffset int32, messageLength int32) {
runtime := arwen.GetRuntimeContext(context)
metering := arwen.GetMeteringContext(context)

// TODO replace with a message coming from the SmartContract
runtime.SignalUserError("user error")

gasToUse := metering.GasSchedule().ElrondAPICost.SignalError
metering.UseGas(gasToUse)
}

//export signalExit
func signalExit(context unsafe.Pointer, exitCode int32) {
runtime := arwen.GetRuntimeContext(context)
metering := arwen.GetMeteringContext(context)

runtime.SignalExit(int(exitCode))
message, err := runtime.MemLoad(messageOffset, messageLength)
if withFault(err, context) {
return
}
runtime.SignalUserError(string(message))

// TODO replace with a gas cost specific to SignalExit
gasToUse := metering.GasSchedule().ElrondAPICost.SignalError
metering.UseGas(gasToUse)
}
Expand Down Expand Up @@ -387,6 +384,22 @@ func transferValue(context unsafe.Pointer, gasLimit int64, destOffset int32, val
return 0
}

//export getArgumentLength
func getArgumentLength(context unsafe.Pointer, id int32) int32 {
runtime := arwen.GetRuntimeContext(context)
metering := arwen.GetMeteringContext(context)

gasToUse := metering.GasSchedule().ElrondAPICost.GetArgument
metering.UseGas(gasToUse)

args := runtime.Arguments()
if id < 0 || int32(len(args)) <= id {
return -1
}

return int32(len(args[id]))
}

//export getArgument
func getArgument(context unsafe.Pointer, id int32, argOffset int32) int32 {
runtime := arwen.GetRuntimeContext(context)
Expand All @@ -396,7 +409,7 @@ func getArgument(context unsafe.Pointer, id int32, argOffset int32) int32 {
metering.UseGas(gasToUse)

args := runtime.Arguments()
if int32(len(args)) <= id {
if id < 0 || int32(len(args)) <= id {
return -1
}

Expand Down Expand Up @@ -458,6 +471,25 @@ func storageStore(context unsafe.Pointer, keyOffset int32, dataOffset int32, dat
return storage.SetStorage(runtime.GetSCAddress(), key, data)
}

//export storageGetValueLength
func storageGetValueLength(context unsafe.Pointer, keyOffset int32) int32 {
runtime := arwen.GetRuntimeContext(context)
storage := arwen.GetStorageContext(context)
metering := arwen.GetMeteringContext(context)

key, err := runtime.MemLoad(keyOffset, arwen.HashLen)
if withFault(err, context) {
return -1
}

data := storage.GetStorage(runtime.GetSCAddress(), key)

gasToUse := metering.GasSchedule().ElrondAPICost.StorageLoad
metering.UseGas(gasToUse)

return int32(len(data))
}

//export storageLoad
func storageLoad(context unsafe.Pointer, keyOffset int32, dataOffset int32) int32 {
runtime := arwen.GetRuntimeContext(context)
Expand Down
13 changes: 10 additions & 3 deletions cmd/test/debugArwen.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@ func main() {
}
jsonTestPath := os.Args[1]

testExec := newArwenTestExecutor().replaceCode(
"erc20.wasm",
filepath.Join(getTestRoot(), "contracts/erc20-c.wasm"))
testExec := newArwenTestExecutor().
replaceCode(
"erc20.wasm",
filepath.Join(getTestRoot(), "contracts/simple-coin.wasm")).
replaceCode(
"crypto-bubbles.wasm",
filepath.Join(getTestRoot(), "contracts/crypto-bubbles.wasm")).
replaceCode(
"features.wasm",
filepath.Join(getTestRoot(), "contracts/features.wasm"))
err := controller.RunSingleJSONTest(
jsonTestPath,
testExec)
Expand Down
42 changes: 31 additions & 11 deletions cmd/test/executorRun.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

arwen "github.com/ElrondNetwork/arwen-wasm-vm/arwen/host"
"github.com/ElrondNetwork/arwen-wasm-vm/config"
vmcommon "github.com/ElrondNetwork/elrond-vm-common"
vmi "github.com/ElrondNetwork/elrond-vm-common"
worldhook "github.com/ElrondNetwork/elrond-vm-util/mock-hook-blockchain"
cryptohook "github.com/ElrondNetwork/elrond-vm-util/mock-hook-crypto"
Expand Down Expand Up @@ -100,7 +101,21 @@ func (te *arwenTestExecutor) Run(test *ij.Test) error {
}
var output *vmi.VMOutput

if tx.IsCreate {
sender := world.AcctMap.GetAccount(tx.From)
if sender.Balance.Cmp(tx.Value) < 0 {
// out of funds is handled by the protocol, so needs to be mocked here
output = &vmcommon.VMOutput{
ReturnData: make([][]byte, 0),
ReturnCode: vmcommon.OutOfFunds,
ReturnMessage: "",
GasRemaining: 0,
GasRefund: big.NewInt(0),
OutputAccounts: make(map[string]*vmcommon.OutputAccount),
DeletedAccounts: make([][]byte, 0),
TouchedAccounts: make([][]byte, 0),
Logs: make([]*vmcommon.LogEntry, 0),
}
} else if tx.IsCreate {
input := &vmi.ContractCreateInput{
ContractCode: []byte(tx.AssembledCode),
VMInput: vmi.VMInput{
Expand Down Expand Up @@ -153,20 +168,20 @@ func (te *arwenTestExecutor) Run(test *ij.Test) error {
if updErr != nil {
return updErr
}

// sum of all balance deltas should equal call value (unless we got an error)
sumOfBalanceDeltas := big.NewInt(0)
for _, oa := range output.OutputAccounts {
sumOfBalanceDeltas = sumOfBalanceDeltas.Add(sumOfBalanceDeltas, oa.BalanceDelta)
}
if sumOfBalanceDeltas.Cmp(tx.Value) != 0 {
return fmt.Errorf("sum of balance deltas should equal call value. Sum of balance deltas: %d (0x%x). Call value: %d (0x%x)",
sumOfBalanceDeltas, sumOfBalanceDeltas, tx.Value, tx.Value)
}
}

blResult := block.Results[txIndex]

// sum of all balance deltas should equal call value
sumOfBalanceDeltas := big.NewInt(0)
for _, oa := range output.OutputAccounts {
sumOfBalanceDeltas = sumOfBalanceDeltas.Add(sumOfBalanceDeltas, oa.BalanceDelta)
}
if sumOfBalanceDeltas.Cmp(tx.Value) != 0 {
return fmt.Errorf("sum of balance deltas should equal call value. Sum of balance deltas: %d (0x%x). Call value: %d (0x%x)",
sumOfBalanceDeltas, sumOfBalanceDeltas, tx.Value, tx.Value)
}

// check return code
expectedStatus := 0
if blResult.Status != nil {
Expand All @@ -176,6 +191,11 @@ func (te *arwenTestExecutor) Run(test *ij.Test) error {
return fmt.Errorf("result code mismatch. Tx #%d. Want: %d. Have: %d", txIndex, expectedStatus, int(output.ReturnCode))
}

if output.ReturnMessage != blResult.Message {
return fmt.Errorf("result message mismatch. Tx #%d. Want: %s. Have: %s",
txIndex, blResult.Message, output.ReturnMessage)
}

// check result
if len(output.ReturnData) != len(blResult.Out) {
return fmt.Errorf("result length mismatch. Tx #%d. Want: %s. Have: %s",
Expand Down
36 changes: 26 additions & 10 deletions cmd/test/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
controller "github.com/ElrondNetwork/elrond-vm-util/test-util/testcontroller"
)

var excludedTests = []string{}

func TestErc20FromC(t *testing.T) {
testExec := newArwenTestExecutor().replaceCode(
"erc20.wasm",
Expand All @@ -18,39 +16,40 @@ func TestErc20FromC(t *testing.T) {
getTestRoot(),
"erc20",
".json",
excludedTests,
[]string{},
testExec)

if err != nil {
t.Error(err)
}
}

func TestErc20FromRustDebug(t *testing.T) {
func TestErc20FromRust(t *testing.T) {
testExec := newArwenTestExecutor().replaceCode(
"erc20.wasm",
filepath.Join(getTestRoot(), "contracts/erc20-rust-debug.wasm"))
filepath.Join(getTestRoot(), "contracts/simple-coin.wasm"))

err := controller.RunAllJSONTestsInDirectory(
getTestRoot(),
"erc20",
".json",
excludedTests,
[]string{},
testExec)

if err != nil {
t.Error(err)
}
}

func TestErc20FromRustRelease(t *testing.T) {
func TestCryptoBubbles(t *testing.T) {
testExec := newArwenTestExecutor().replaceCode(
"erc20.wasm",
filepath.Join(getTestRoot(), "contracts/erc20-rust-release.wasm"))
"crypto-bubbles.wasm",
filepath.Join(getTestRoot(), "contracts/crypto-bubbles.wasm"))
excludedTests := []string{}

err := controller.RunAllJSONTestsInDirectory(
getTestRoot(),
"erc20",
"crypto_bubbles_min_v1",
".json",
excludedTests,
testExec)
Expand All @@ -59,3 +58,20 @@ func TestErc20FromRustRelease(t *testing.T) {
t.Error(err)
}
}

func TestFeaturesFromRust(t *testing.T) {
testExec := newArwenTestExecutor().replaceCode(
"features.wasm",
filepath.Join(getTestRoot(), "contracts/features.wasm"))

err := controller.RunAllJSONTestsInDirectory(
getTestRoot(),
"features",
".json",
[]string{},
testExec)

if err != nil {
t.Error(err)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.13
require (
github.com/ElrondNetwork/big-int-util v0.0.5
github.com/ElrondNetwork/elrond-vm-common v0.1.9
github.com/ElrondNetwork/elrond-vm-util v0.1.1
github.com/ElrondNetwork/elrond-vm-util v0.1.3
github.com/mitchellh/mapstructure v1.1.2
github.com/stretchr/testify v1.4.0
)
Loading

0 comments on commit 61e706e

Please sign in to comment.