|
@ -9,6 +9,8 @@ import ( |
|
|
"time" |
|
|
"time" |
|
|
|
|
|
|
|
|
. "github.com/tendermint/tendermint/common" |
|
|
. "github.com/tendermint/tendermint/common" |
|
|
|
|
|
"github.com/tendermint/tendermint/events" |
|
|
|
|
|
"github.com/tendermint/tendermint/types" |
|
|
. "github.com/tendermint/tendermint/vm" |
|
|
. "github.com/tendermint/tendermint/vm" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
@ -35,6 +37,7 @@ func makeBytes(n int) []byte { |
|
|
return b |
|
|
return b |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Runs a basic loop
|
|
|
func TestVM(t *testing.T) { |
|
|
func TestVM(t *testing.T) { |
|
|
ourVm := NewVM(newAppState(), newParams(), Zero256, nil) |
|
|
ourVm := NewVM(newAppState(), newParams(), Zero256, nil) |
|
|
|
|
|
|
|
@ -46,8 +49,8 @@ func TestVM(t *testing.T) { |
|
|
Address: Uint64ToWord256(101), |
|
|
Address: Uint64ToWord256(101), |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var gas uint64 = 1000 |
|
|
|
|
|
N := []byte{0xff, 0xff} |
|
|
|
|
|
|
|
|
var gas uint64 = 100000 |
|
|
|
|
|
N := []byte{0x0f, 0x0f} |
|
|
// Loop N times
|
|
|
// Loop N times
|
|
|
code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)} |
|
|
code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)} |
|
|
for i := 0; i < len(N); i++ { |
|
|
for i := 0; i < len(N); i++ { |
|
@ -58,8 +61,12 @@ func TestVM(t *testing.T) { |
|
|
output, err := ourVm.Call(account1, account2, code, []byte{}, 0, &gas) |
|
|
output, err := ourVm.Call(account1, account2, code, []byte{}, 0, &gas) |
|
|
fmt.Printf("Output: %v Error: %v\n", output, err) |
|
|
fmt.Printf("Output: %v Error: %v\n", output, err) |
|
|
fmt.Println("Call took:", time.Since(start)) |
|
|
fmt.Println("Call took:", time.Since(start)) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
t.Fatal(err) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Tests the code for a subcurrency contract compiled by serpent
|
|
|
func TestSubcurrency(t *testing.T) { |
|
|
func TestSubcurrency(t *testing.T) { |
|
|
st := newAppState() |
|
|
st := newAppState() |
|
|
// Create accounts
|
|
|
// Create accounts
|
|
@ -86,7 +93,103 @@ func TestSubcurrency(t *testing.T) { |
|
|
data, _ := hex.DecodeString("693200CE0000000000000000000000004B4363CDE27C2EB05E66357DB05BC5C88F850C1A0000000000000000000000000000000000000000000000000000000000000005") |
|
|
data, _ := hex.DecodeString("693200CE0000000000000000000000004B4363CDE27C2EB05E66357DB05BC5C88F850C1A0000000000000000000000000000000000000000000000000000000000000005") |
|
|
output, err := ourVm.Call(account1, account2, code, data, 0, &gas) |
|
|
output, err := ourVm.Call(account1, account2, code, data, 0, &gas) |
|
|
fmt.Printf("Output: %v Error: %v\n", output, err) |
|
|
fmt.Printf("Output: %v Error: %v\n", output, err) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
t.Fatal(err) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Test sending tokens from a contract to another account
|
|
|
|
|
|
func TestSendCall(t *testing.T) { |
|
|
|
|
|
fakeAppState := newAppState() |
|
|
|
|
|
ourVm := NewVM(fakeAppState, newParams(), Zero256, nil) |
|
|
|
|
|
|
|
|
|
|
|
// Create accounts
|
|
|
|
|
|
account1 := &Account{ |
|
|
|
|
|
Address: Uint64ToWord256(100), |
|
|
|
|
|
} |
|
|
|
|
|
account2 := &Account{ |
|
|
|
|
|
Address: Uint64ToWord256(101), |
|
|
|
|
|
} |
|
|
|
|
|
account3 := &Account{ |
|
|
|
|
|
Address: Uint64ToWord256(102), |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// account1 will call account2 which will trigger CALL opcode to account3
|
|
|
|
|
|
addr := account3.Address.Postfix(20) |
|
|
|
|
|
contractCode := callContractCode(addr) |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------
|
|
|
|
|
|
// account2 has insufficient balance, should fail
|
|
|
|
|
|
|
|
|
|
|
|
exception := runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 1000) |
|
|
|
|
|
if exception == "" { |
|
|
|
|
|
t.Fatal("Expected exception") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------
|
|
|
|
|
|
// give account2 sufficient balance, should pass
|
|
|
|
|
|
|
|
|
|
|
|
account2.Balance = 100000 |
|
|
|
|
|
exception = runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 1000) |
|
|
|
|
|
if exception != "" { |
|
|
|
|
|
t.Fatal("Unexpected exception", exception) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------
|
|
|
|
|
|
// insufficient gas, should fail
|
|
|
|
|
|
|
|
|
|
|
|
account2.Balance = 100000 |
|
|
|
|
|
exception = runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 100) |
|
|
|
|
|
if exception == "" { |
|
|
|
|
|
t.Fatal("Expected exception") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// subscribes to an AccReceive, runs the vm, returns the exception
|
|
|
|
|
|
func runVMWaitEvents(t *testing.T, ourVm *VM, caller, callee *Account, subscribeAddr, contractCode []byte, gas uint64) string { |
|
|
|
|
|
// we need to catch the event from the CALL to check for exceptions
|
|
|
|
|
|
evsw := new(events.EventSwitch) |
|
|
|
|
|
evsw.Start() |
|
|
|
|
|
ch := make(chan interface{}) |
|
|
|
|
|
fmt.Printf("subscribe to %x\n", subscribeAddr) |
|
|
|
|
|
evsw.AddListenerForEvent("test", types.EventStringAccReceive(subscribeAddr), func(msg interface{}) { |
|
|
|
|
|
ch <- msg |
|
|
|
|
|
}) |
|
|
|
|
|
evc := events.NewEventCache(evsw) |
|
|
|
|
|
ourVm.SetFireable(evc) |
|
|
|
|
|
go func() { |
|
|
|
|
|
start := time.Now() |
|
|
|
|
|
output, err := ourVm.Call(caller, callee, contractCode, []byte{}, 0, &gas) |
|
|
|
|
|
fmt.Printf("Output: %v Error: %v\n", output, err) |
|
|
|
|
|
fmt.Println("Call took:", time.Since(start)) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
ch <- err.Error() |
|
|
|
|
|
} |
|
|
|
|
|
evc.Flush() |
|
|
|
|
|
}() |
|
|
|
|
|
msg := <-ch |
|
|
|
|
|
switch ev := msg.(type) { |
|
|
|
|
|
case types.EventMsgCallTx: |
|
|
|
|
|
return ev.Exception |
|
|
|
|
|
case types.EventMsgCall: |
|
|
|
|
|
return ev.Exception |
|
|
|
|
|
case string: |
|
|
|
|
|
return ev |
|
|
|
|
|
} |
|
|
|
|
|
return "" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// this is code to call another contract (hardcoded as addr)
|
|
|
|
|
|
func callContractCode(addr []byte) []byte { |
|
|
|
|
|
gas1, gas2 := byte(0x1), byte(0x1) |
|
|
|
|
|
value := byte(0x69) |
|
|
|
|
|
inOff, inSize := byte(0x0), byte(0x0) // no call data
|
|
|
|
|
|
retOff, retSize := byte(0x0), byte(0x20) |
|
|
|
|
|
// this is the code we want to run (send funds to an account and return)
|
|
|
|
|
|
contractCode := []byte{0x60, retSize, 0x60, retOff, 0x60, inSize, 0x60, inOff, 0x60, value, 0x73} |
|
|
|
|
|
contractCode = append(contractCode, addr...) |
|
|
|
|
|
contractCode = append(contractCode, []byte{0x61, gas1, gas2, 0xf1, 0x60, 0x20, 0x60, 0x0, 0xf3}...) |
|
|
|
|
|
return contractCode |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|