|
@ -1,6 +1,7 @@ |
|
|
package state |
|
|
package state |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
|
|
|
"bytes" |
|
|
"fmt" |
|
|
"fmt" |
|
|
"strconv" |
|
|
"strconv" |
|
|
"testing" |
|
|
"testing" |
|
@ -22,7 +23,7 @@ x - 1 input, no perm, call perm, create perm |
|
|
x - 1 input, perm |
|
|
x - 1 input, perm |
|
|
x - 2 inputs, one with perm one without |
|
|
x - 2 inputs, one with perm one without |
|
|
|
|
|
|
|
|
- CallTx |
|
|
|
|
|
|
|
|
- CallTx, CALL |
|
|
x - 1 input, no perm, send perm, create perm |
|
|
x - 1 input, no perm, send perm, create perm |
|
|
x - 1 input, perm |
|
|
x - 1 input, perm |
|
|
x - contract runs call but doesn't have call perm |
|
|
x - contract runs call but doesn't have call perm |
|
@ -30,26 +31,28 @@ x - contract runs call and has call perm |
|
|
x - contract runs call (with perm), runs contract that runs call (without perm) |
|
|
x - contract runs call (with perm), runs contract that runs call (without perm) |
|
|
x - contract runs call (with perm), runs contract that runs call (with perm) |
|
|
x - contract runs call (with perm), runs contract that runs call (with perm) |
|
|
|
|
|
|
|
|
- CallTx (Create) |
|
|
|
|
|
|
|
|
- CallTx for Create, CREATE |
|
|
x - 1 input, no perm, send perm, call perm |
|
|
x - 1 input, no perm, send perm, call perm |
|
|
- 1 input, perm |
|
|
|
|
|
- contract runs create but doesn't have create perm |
|
|
|
|
|
- contract runs create but has perm |
|
|
|
|
|
- contract runs call with empty address (has call perm, not create perm) |
|
|
|
|
|
- contract runs call with empty address (has call perm, and create perm) |
|
|
|
|
|
|
|
|
x - 1 input, perm |
|
|
|
|
|
x - contract runs create but doesn't have create perm |
|
|
|
|
|
x - contract runs create but has perm |
|
|
|
|
|
x - contract runs call with empty address (has call and create perm) |
|
|
|
|
|
|
|
|
- BondTx |
|
|
- BondTx |
|
|
- 1 input, no perm |
|
|
- 1 input, no perm |
|
|
- 1 input, perm |
|
|
- 1 input, perm |
|
|
- 2 inputs, one with perm one without |
|
|
- 2 inputs, one with perm one without |
|
|
|
|
|
|
|
|
- Gendoug: get/set/add/rm |
|
|
|
|
|
|
|
|
- SendTx for new account ? CALL for new account? |
|
|
|
|
|
|
|
|
|
|
|
- Gendoug: |
|
|
|
|
|
- base: has,set,unset |
|
|
|
|
|
- roles: has, add, r |
|
|
|
|
|
|
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
// keys
|
|
|
// keys
|
|
|
var ( |
|
|
|
|
|
user = makeUsers(5) |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
var user = makeUsers(5) |
|
|
|
|
|
|
|
|
func makeUsers(n int) []*account.PrivAccount { |
|
|
func makeUsers(n int) []*account.PrivAccount { |
|
|
accounts := []*account.PrivAccount{} |
|
|
accounts := []*account.PrivAccount{} |
|
@ -253,19 +256,6 @@ func TestSendPermission(t *testing.T) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// convenience function for contract that calls a given address
|
|
|
|
|
|
func callContractCode(contractAddr []byte) []byte { |
|
|
|
|
|
gas1, gas2 := byte(0x1), byte(0x1) |
|
|
|
|
|
value := byte(0x1) |
|
|
|
|
|
inOff, inSize := byte(0x0), byte(0x0) // no call data
|
|
|
|
|
|
retOff, retSize := byte(0x0), byte(0x20) |
|
|
|
|
|
// this is the code we want to run (call a contract and return)
|
|
|
|
|
|
contractCode := []byte{0x60, retSize, 0x60, retOff, 0x60, inSize, 0x60, inOff, 0x60, value, 0x73} |
|
|
|
|
|
contractCode = append(contractCode, contractAddr...) |
|
|
|
|
|
contractCode = append(contractCode, []byte{0x61, gas1, gas2, 0xf1, 0x60, 0x20, 0x60, 0x0, 0xf3}...) |
|
|
|
|
|
return contractCode |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestCallPermission(t *testing.T) { |
|
|
func TestCallPermission(t *testing.T) { |
|
|
stateDB := dbm.GetDB("state") |
|
|
stateDB := dbm.GetDB("state") |
|
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) |
|
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) |
|
@ -318,7 +308,7 @@ func TestCallPermission(t *testing.T) { |
|
|
SignCallTx(tx, user[0]) |
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
exception := execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
|
|
|
|
|
|
|
_, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) //
|
|
|
if exception == "" { |
|
|
if exception == "" { |
|
|
t.Fatal("Expected exception") |
|
|
t.Fatal("Expected exception") |
|
|
} |
|
|
} |
|
@ -334,7 +324,7 @@ func TestCallPermission(t *testing.T) { |
|
|
SignCallTx(tx, user[0]) |
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
exception = execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
|
|
|
|
|
|
|
_, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) //
|
|
|
if exception != "" { |
|
|
if exception != "" { |
|
|
t.Fatal("Unexpected exception:", exception) |
|
|
t.Fatal("Unexpected exception:", exception) |
|
|
} |
|
|
} |
|
@ -364,7 +354,7 @@ func TestCallPermission(t *testing.T) { |
|
|
SignCallTx(tx, user[0]) |
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
exception = execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
|
|
|
|
|
|
|
_, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) //
|
|
|
if exception == "" { |
|
|
if exception == "" { |
|
|
t.Fatal("Expected exception") |
|
|
t.Fatal("Expected exception") |
|
|
} |
|
|
} |
|
@ -382,19 +372,249 @@ func TestCallPermission(t *testing.T) { |
|
|
SignCallTx(tx, user[0]) |
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
exception = execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
|
|
|
|
|
|
|
_, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) //
|
|
|
if exception != "" { |
|
|
if exception != "" { |
|
|
t.Fatal("Unexpected exception", exception) |
|
|
t.Fatal("Unexpected exception", exception) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestCreatePermission(t *testing.T) { |
|
|
|
|
|
stateDB := dbm.GetDB("state") |
|
|
|
|
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) |
|
|
|
|
|
genDoc.Accounts[0].Permissions.Base.Set(ptypes.Create, true) // give the 0 account permission
|
|
|
|
|
|
genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission
|
|
|
|
|
|
st := MakeGenesisState(stateDB, &genDoc) |
|
|
|
|
|
blockCache := NewBlockCache(st) |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// create a simple contract
|
|
|
|
|
|
fmt.Println("##### CREATE SIMPLE CONTRACT") |
|
|
|
|
|
|
|
|
|
|
|
contractCode := []byte{0x60} |
|
|
|
|
|
createCode := wrapContractForCreate(contractCode) |
|
|
|
|
|
|
|
|
|
|
|
// A single input, having the permission, should succeed
|
|
|
|
|
|
tx, _ := NewCallTx(blockCache, user[0].PubKey, nil, createCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
if err := ExecTx(blockCache, tx, true, nil); err != nil { |
|
|
|
|
|
t.Fatal("Transaction failed", err) |
|
|
|
|
|
} |
|
|
|
|
|
// ensure the contract is there
|
|
|
|
|
|
contractAddr := NewContractAddress(tx.Input.Address, uint64(tx.Input.Sequence)) |
|
|
|
|
|
contractAcc := blockCache.GetAccount(contractAddr) |
|
|
|
|
|
if contractAcc == nil { |
|
|
|
|
|
t.Fatalf("failed to create contract %X", contractAddr) |
|
|
|
|
|
} |
|
|
|
|
|
if bytes.Compare(contractAcc.Code, contractCode) != 0 { |
|
|
|
|
|
t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.Code, contractCode) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// create contract that uses the CREATE op
|
|
|
|
|
|
fmt.Println("##### CREATE FACTORY") |
|
|
|
|
|
|
|
|
|
|
|
contractCode = []byte{0x60} |
|
|
|
|
|
createCode = wrapContractForCreate(contractCode) |
|
|
|
|
|
factoryCode := createContractCode() |
|
|
|
|
|
createFactoryCode := wrapContractForCreate(factoryCode) |
|
|
|
|
|
|
|
|
|
|
|
// A single input, having the permission, should succeed
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, nil, createFactoryCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
if err := ExecTx(blockCache, tx, true, nil); err != nil { |
|
|
|
|
|
t.Fatal("Transaction failed", err) |
|
|
|
|
|
} |
|
|
|
|
|
// ensure the contract is there
|
|
|
|
|
|
contractAddr = NewContractAddress(tx.Input.Address, uint64(tx.Input.Sequence)) |
|
|
|
|
|
contractAcc = blockCache.GetAccount(contractAddr) |
|
|
|
|
|
if contractAcc == nil { |
|
|
|
|
|
t.Fatalf("failed to create contract %X", contractAddr) |
|
|
|
|
|
} |
|
|
|
|
|
if bytes.Compare(contractAcc.Code, factoryCode) != 0 { |
|
|
|
|
|
t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.Code, factoryCode) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// call the contract (should FAIL)
|
|
|
|
|
|
fmt.Println("###### CALL THE FACTORY (FAIL)") |
|
|
|
|
|
|
|
|
|
|
|
// A single input, having the permission, should succeed
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
|
|
|
_, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(contractAddr)) //
|
|
|
|
|
|
if exception == "" { |
|
|
|
|
|
t.Fatal("expected exception") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// call the contract (should PASS)
|
|
|
|
|
|
fmt.Println("###### CALL THE FACTORY (PASS)") |
|
|
|
|
|
|
|
|
|
|
|
contractAcc.Permissions.Base.Set(ptypes.Create, true) |
|
|
|
|
|
blockCache.UpdateAccount(contractAcc) |
|
|
|
|
|
|
|
|
|
|
|
// A single input, having the permission, should succeed
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
|
|
|
_, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(contractAddr)) //
|
|
|
|
|
|
if exception != "" { |
|
|
|
|
|
t.Fatal("unexpected exception", exception) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------
|
|
|
|
|
|
fmt.Println("##### CALL to empty address") |
|
|
|
|
|
zeroAddr := LeftPadBytes([]byte{}, 20) |
|
|
|
|
|
code := callContractCode(zeroAddr) |
|
|
|
|
|
|
|
|
|
|
|
contractAddr = NewContractAddress(user[0].Address, 110) |
|
|
|
|
|
contractAcc = &account.Account{ |
|
|
|
|
|
Address: contractAddr, |
|
|
|
|
|
Balance: 1000, |
|
|
|
|
|
Code: code, |
|
|
|
|
|
Sequence: 0, |
|
|
|
|
|
StorageRoot: Zero256.Bytes(), |
|
|
|
|
|
Permissions: ptypes.NewAccountPermissions(), |
|
|
|
|
|
} |
|
|
|
|
|
contractAcc.Permissions.Base.Set(ptypes.Call, true) |
|
|
|
|
|
contractAcc.Permissions.Base.Set(ptypes.Create, true) |
|
|
|
|
|
blockCache.UpdateAccount(contractAcc) |
|
|
|
|
|
|
|
|
|
|
|
// this should call the 0 address but not create ...
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 10000, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
|
|
|
_, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(zeroAddr)) //
|
|
|
|
|
|
if exception != "" { |
|
|
|
|
|
t.Fatal("unexpected exception", exception) |
|
|
|
|
|
} |
|
|
|
|
|
zeroAcc := blockCache.GetAccount(zeroAddr) |
|
|
|
|
|
if len(zeroAcc.Code) != 0 { |
|
|
|
|
|
t.Fatal("the zero account was given code from a CALL!") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestBondPermission(t *testing.T) { |
|
|
|
|
|
stateDB := dbm.GetDB("state") |
|
|
|
|
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) |
|
|
|
|
|
st := MakeGenesisState(stateDB, &genDoc) |
|
|
|
|
|
blockCache := NewBlockCache(st) |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// a bond tx from someone without bond perm should fail
|
|
|
|
|
|
tx, _ := NewCallTx(blockCache, user[0].PubKey, nil, createCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
if err := ExecTx(blockCache, tx, true, nil); err != nil { |
|
|
|
|
|
t.Fatal("Transaction failed", err) |
|
|
|
|
|
} |
|
|
|
|
|
// ensure the contract is there
|
|
|
|
|
|
contractAddr := NewContractAddress(tx.Input.Address, uint64(tx.Input.Sequence)) |
|
|
|
|
|
contractAcc := blockCache.GetAccount(contractAddr) |
|
|
|
|
|
if contractAcc == nil { |
|
|
|
|
|
t.Fatalf("failed to create contract %X", contractAddr) |
|
|
|
|
|
} |
|
|
|
|
|
if bytes.Compare(contractAcc.Code, contractCode) != 0 { |
|
|
|
|
|
t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.Code, contractCode) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// create contract that uses the CREATE op
|
|
|
|
|
|
fmt.Println("##### CREATE FACTORY") |
|
|
|
|
|
|
|
|
|
|
|
contractCode = []byte{0x60} |
|
|
|
|
|
createCode = wrapContractForCreate(contractCode) |
|
|
|
|
|
factoryCode := createContractCode() |
|
|
|
|
|
createFactoryCode := wrapContractForCreate(factoryCode) |
|
|
|
|
|
|
|
|
|
|
|
// A single input, having the permission, should succeed
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, nil, createFactoryCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
if err := ExecTx(blockCache, tx, true, nil); err != nil { |
|
|
|
|
|
t.Fatal("Transaction failed", err) |
|
|
|
|
|
} |
|
|
|
|
|
// ensure the contract is there
|
|
|
|
|
|
contractAddr = NewContractAddress(tx.Input.Address, uint64(tx.Input.Sequence)) |
|
|
|
|
|
contractAcc = blockCache.GetAccount(contractAddr) |
|
|
|
|
|
if contractAcc == nil { |
|
|
|
|
|
t.Fatalf("failed to create contract %X", contractAddr) |
|
|
|
|
|
} |
|
|
|
|
|
if bytes.Compare(contractAcc.Code, factoryCode) != 0 { |
|
|
|
|
|
t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.Code, factoryCode) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// call the contract (should FAIL)
|
|
|
|
|
|
fmt.Println("###### CALL THE FACTORY (FAIL)") |
|
|
|
|
|
|
|
|
|
|
|
// A single input, having the permission, should succeed
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
|
|
|
_, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(contractAddr)) //
|
|
|
|
|
|
if exception == "" { |
|
|
|
|
|
t.Fatal("expected exception") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
// call the contract (should PASS)
|
|
|
|
|
|
fmt.Println("###### CALL THE FACTORY (PASS)") |
|
|
|
|
|
|
|
|
|
|
|
contractAcc.Permissions.Base.Set(ptypes.Create, true) |
|
|
|
|
|
blockCache.UpdateAccount(contractAcc) |
|
|
|
|
|
|
|
|
|
|
|
// A single input, having the permission, should succeed
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
|
|
|
_, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(contractAddr)) //
|
|
|
|
|
|
if exception != "" { |
|
|
|
|
|
t.Fatal("unexpected exception", exception) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------
|
|
|
|
|
|
fmt.Println("##### CALL to empty address") |
|
|
|
|
|
zeroAddr := LeftPadBytes([]byte{}, 20) |
|
|
|
|
|
code := callContractCode(zeroAddr) |
|
|
|
|
|
|
|
|
|
|
|
contractAddr = NewContractAddress(user[0].Address, 110) |
|
|
|
|
|
contractAcc = &account.Account{ |
|
|
|
|
|
Address: contractAddr, |
|
|
|
|
|
Balance: 1000, |
|
|
|
|
|
Code: code, |
|
|
|
|
|
Sequence: 0, |
|
|
|
|
|
StorageRoot: Zero256.Bytes(), |
|
|
|
|
|
Permissions: ptypes.NewAccountPermissions(), |
|
|
|
|
|
} |
|
|
|
|
|
contractAcc.Permissions.Base.Set(ptypes.Call, true) |
|
|
|
|
|
contractAcc.Permissions.Base.Set(ptypes.Create, true) |
|
|
|
|
|
blockCache.UpdateAccount(contractAcc) |
|
|
|
|
|
|
|
|
|
|
|
// this should call the 0 address but not create ...
|
|
|
|
|
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 10000, 100) |
|
|
|
|
|
SignCallTx(tx, user[0]) |
|
|
|
|
|
// we need to subscribe to the Receive event to detect the exception
|
|
|
|
|
|
_, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(zeroAddr)) //
|
|
|
|
|
|
if exception != "" { |
|
|
|
|
|
t.Fatal("unexpected exception", exception) |
|
|
|
|
|
} |
|
|
|
|
|
zeroAcc := blockCache.GetAccount(zeroAddr) |
|
|
|
|
|
if len(zeroAcc.Code) != 0 { |
|
|
|
|
|
t.Fatal("the zero account was given code from a CALL!") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
|
|
// helpers
|
|
|
|
|
|
|
|
|
// run ExecTx and wait for the Receive event on given addr
|
|
|
// run ExecTx and wait for the Receive event on given addr
|
|
|
// returns error/exception
|
|
|
|
|
|
func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, addr []byte) string { |
|
|
|
|
|
|
|
|
// returns the msg data and an error/exception
|
|
|
|
|
|
func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid string) (interface{}, string) { |
|
|
evsw := new(events.EventSwitch) |
|
|
evsw := new(events.EventSwitch) |
|
|
evsw.Start() |
|
|
evsw.Start() |
|
|
ch := make(chan interface{}) |
|
|
ch := make(chan interface{}) |
|
|
evsw.AddListenerForEvent("test", types.EventStringAccReceive(addr), func(msg interface{}) { |
|
|
|
|
|
|
|
|
evsw.AddListenerForEvent("test", eventid, func(msg interface{}) { |
|
|
ch <- msg |
|
|
ch <- msg |
|
|
}) |
|
|
}) |
|
|
evc := events.NewEventCache(evsw) |
|
|
evc := events.NewEventCache(evsw) |
|
@ -407,12 +627,57 @@ func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, addr []b |
|
|
msg := <-ch |
|
|
msg := <-ch |
|
|
switch ev := msg.(type) { |
|
|
switch ev := msg.(type) { |
|
|
case types.EventMsgCallTx: |
|
|
case types.EventMsgCallTx: |
|
|
return ev.Exception |
|
|
|
|
|
|
|
|
return ev, ev.Exception |
|
|
case types.EventMsgCall: |
|
|
case types.EventMsgCall: |
|
|
return ev.Exception |
|
|
|
|
|
|
|
|
return ev, ev.Exception |
|
|
case string: |
|
|
case string: |
|
|
return ev |
|
|
|
|
|
|
|
|
return nil, ev |
|
|
|
|
|
default: |
|
|
|
|
|
return ev, "" |
|
|
} |
|
|
} |
|
|
return "" |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// convenience function for contract that calls a given address
|
|
|
|
|
|
func callContractCode(contractAddr []byte) []byte { |
|
|
|
|
|
// calldatacopy into mem and use as input to call
|
|
|
|
|
|
memOff, inputOff := byte(0x0), byte(0x0) |
|
|
|
|
|
contractCode := []byte{0x60, memOff, 0x60, inputOff, 0x36, 0x37} |
|
|
|
|
|
|
|
|
|
|
|
gas1, gas2 := byte(0x1), byte(0x1) |
|
|
|
|
|
value := byte(0x1) |
|
|
|
|
|
inOff := byte(0x0) |
|
|
|
|
|
retOff, retSize := byte(0x0), byte(0x20) |
|
|
|
|
|
// this is the code we want to run (call a contract and return)
|
|
|
|
|
|
contractCode = append(contractCode, []byte{0x60, retSize, 0x60, retOff, 0x36, 0x60, inOff, 0x60, value, 0x73}...) |
|
|
|
|
|
contractCode = append(contractCode, contractAddr...) |
|
|
|
|
|
contractCode = append(contractCode, []byte{0x61, gas1, gas2, 0xf1, 0x60, 0x20, 0x60, 0x0, 0xf3}...) |
|
|
|
|
|
return contractCode |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// convenience function for contract that is a factory for the code that comes as call data
|
|
|
|
|
|
func createContractCode() []byte { |
|
|
|
|
|
// TODO: gas ...
|
|
|
|
|
|
|
|
|
|
|
|
// calldatacopy the calldatasize
|
|
|
|
|
|
memOff, inputOff := byte(0x0), byte(0x0) |
|
|
|
|
|
contractCode := []byte{0x60, memOff, 0x60, inputOff, 0x36, 0x37} |
|
|
|
|
|
|
|
|
|
|
|
// create
|
|
|
|
|
|
value := byte(0x1) |
|
|
|
|
|
contractCode = append(contractCode, []byte{0x60, value, 0x36, 0x60, memOff, 0xf0}...) |
|
|
|
|
|
return contractCode |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// wrap a contract in create code
|
|
|
|
|
|
func wrapContractForCreate(contractCode []byte) []byte { |
|
|
|
|
|
// the is the code we need to return the contractCode when the contract is initialized
|
|
|
|
|
|
lenCode := len(contractCode) |
|
|
|
|
|
// push code to the stack
|
|
|
|
|
|
code := append([]byte{0x7f}, RightPadWord256(contractCode).Bytes()...) |
|
|
|
|
|
// store it in memory
|
|
|
|
|
|
code = append(code, []byte{0x60, 0x0, 0x52}...) |
|
|
|
|
|
// return whats in memory
|
|
|
|
|
|
code = append(code, []byte{0x60, byte(lenCode), 0x60, 0x0, 0xf3}...) |
|
|
|
|
|
// return init code, contract code, expected return
|
|
|
|
|
|
return code |
|
|
} |
|
|
} |