fix: fevm: update tests for latest actors bundle (#12144)
plus some code improvement refactoring
This commit is contained in:
parent
06a7d74426
commit
d9195c464b
@ -51,50 +51,13 @@ func decodeOutputToUint64(output []byte) (uint64, error) {
|
|||||||
err := binary.Read(buf, binary.BigEndian, &result)
|
err := binary.Read(buf, binary.BigEndian, &result)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
func buildInputFromuint64(number uint64) []byte {
|
func buildInputFromUint64(number uint64) []byte {
|
||||||
// Convert the number to a binary uint64 array
|
// Convert the number to a binary uint64 array
|
||||||
binaryNumber := make([]byte, 8)
|
binaryNumber := make([]byte, 8)
|
||||||
binary.BigEndian.PutUint64(binaryNumber, number)
|
binary.BigEndian.PutUint64(binaryNumber, number)
|
||||||
return inputDataFromArray(binaryNumber)
|
return inputDataFromArray(binaryNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursive delegate calls that fail due to gas limits are currently getting to 229 iterations
|
|
||||||
// before running out of gas
|
|
||||||
func recursiveDelegatecallFail(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) {
|
|
||||||
expectedIterationsBeforeFailing := int(220)
|
|
||||||
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
|
||||||
t.Log("recursion count - ", count)
|
|
||||||
inputData := buildInputFromuint64(count)
|
|
||||||
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData)
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
resultUint, err := decodeOutputToUint64(result)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.NotEqual(t, int(resultUint), int(count))
|
|
||||||
require.Equal(t, expectedIterationsBeforeFailing, int(resultUint))
|
|
||||||
}
|
|
||||||
func recursiveDelegatecallSuccess(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) {
|
|
||||||
t.Log("Count - ", count)
|
|
||||||
|
|
||||||
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
|
||||||
inputData := buildInputFromuint64(count)
|
|
||||||
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
resultUint, err := decodeOutputToUint64(result)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, int(count), int(resultUint))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestFEVMRecursive does a basic fevm contract installation and invocation
|
// TestFEVMRecursive does a basic fevm contract installation and invocation
|
||||||
func TestFEVMRecursive(t *testing.T) {
|
func TestFEVMRecursive(t *testing.T) {
|
||||||
callCounts := []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 230, 330}
|
callCounts := []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 230, 330}
|
||||||
@ -107,7 +70,7 @@ func TestFEVMRecursive(t *testing.T) {
|
|||||||
for _, callCount := range callCounts {
|
for _, callCount := range callCounts {
|
||||||
callCount := callCount // linter unhappy unless callCount is local to loop
|
callCount := callCount // linter unhappy unless callCount is local to loop
|
||||||
t.Run(fmt.Sprintf("TestFEVMRecursive%d", callCount), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestFEVMRecursive%d", callCount), func(t *testing.T) {
|
||||||
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(callCount))
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromUint64(callCount))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -125,7 +88,7 @@ func TestFEVMRecursiveFail(t *testing.T) {
|
|||||||
for _, failCallCount := range failCallCounts {
|
for _, failCallCount := range failCallCounts {
|
||||||
failCallCount := failCallCount // linter unhappy unless callCount is local to loop
|
failCallCount := failCallCount // linter unhappy unless callCount is local to loop
|
||||||
t.Run(fmt.Sprintf("TestFEVMRecursiveFail%d", failCallCount), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestFEVMRecursiveFail%d", failCallCount), func(t *testing.T) {
|
||||||
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(failCallCount))
|
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromUint64(failCallCount))
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Equal(t, exitcode.ExitCode(37), wait.Receipt.ExitCode)
|
require.Equal(t, exitcode.ExitCode(37), wait.Receipt.ExitCode)
|
||||||
})
|
})
|
||||||
@ -156,23 +119,51 @@ func TestFEVMRecursive2(t *testing.T) {
|
|||||||
|
|
||||||
// TestFEVMRecursiveDelegatecallCount tests the maximum delegatecall recursion depth.
|
// TestFEVMRecursiveDelegatecallCount tests the maximum delegatecall recursion depth.
|
||||||
func TestFEVMRecursiveDelegatecallCount(t *testing.T) {
|
func TestFEVMRecursiveDelegatecallCount(t *testing.T) {
|
||||||
|
|
||||||
ctx, cancel, client := kit.SetupFEVMTest(t)
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
highestSuccessCount := uint64(226)
|
// these depend on the actors bundle, may need to be adjusted with a network upgrade
|
||||||
|
const highestSuccessCount = 228
|
||||||
|
const expectedIterationsBeforeFailing = 222
|
||||||
|
|
||||||
filename := "contracts/RecursiveDelegeatecall.hex"
|
filename := "contracts/RecursiveDelegeatecall.hex"
|
||||||
recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(1))
|
|
||||||
recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(2))
|
|
||||||
recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(10))
|
|
||||||
recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(100))
|
|
||||||
recursiveDelegatecallSuccess(ctx, t, client, filename, highestSuccessCount)
|
|
||||||
|
|
||||||
recursiveDelegatecallFail(ctx, t, client, filename, highestSuccessCount+1)
|
testCases := []struct {
|
||||||
recursiveDelegatecallFail(ctx, t, client, filename, uint64(1000))
|
recursionCount uint64
|
||||||
recursiveDelegatecallFail(ctx, t, client, filename, uint64(10000000))
|
expectSuccess bool
|
||||||
|
}{
|
||||||
|
// success
|
||||||
|
{1, true},
|
||||||
|
{2, true},
|
||||||
|
{10, true},
|
||||||
|
{100, true},
|
||||||
|
{highestSuccessCount, true},
|
||||||
|
// failure
|
||||||
|
{highestSuccessCount + 1, false},
|
||||||
|
{1000, false},
|
||||||
|
{10000000, false},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(fmt.Sprintf("recursionCount=%d,expectSuccess=%t", tc.recursionCount, tc.expectSuccess), func(t *testing.T) {
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
inputData := buildInputFromUint64(tc.recursionCount)
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resultUint, err := decodeOutputToUint64(result)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
if tc.expectSuccess {
|
||||||
|
require.Equal(t, int(tc.recursionCount), int(resultUint))
|
||||||
|
} else {
|
||||||
|
require.NotEqual(t, int(resultUint), int(tc.recursionCount), "unexpected recursion count, if the actors bundle has changed, this test may need to be adjusted")
|
||||||
|
require.Equal(t, int(expectedIterationsBeforeFailing), int(resultUint))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFEVMBasic does a basic fevm contract installation and invocation
|
// TestFEVMBasic does a basic fevm contract installation and invocation
|
||||||
@ -585,44 +576,52 @@ func TestFEVMRecursiveActorCall(t *testing.T) {
|
|||||||
filenameActor := "contracts/RecCall.hex"
|
filenameActor := "contracts/RecCall.hex"
|
||||||
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
|
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
|
||||||
|
|
||||||
testN := func(n, r int, ex exitcode.ExitCode) func(t *testing.T) {
|
exitCodeStackOverflow := exitcode.ExitCode(37)
|
||||||
return func(t *testing.T) {
|
exitCodeTransactionReverted := exitcode.ExitCode(33)
|
||||||
inputData := make([]byte, 32*3)
|
|
||||||
binary.BigEndian.PutUint64(inputData[24:], uint64(n))
|
|
||||||
binary.BigEndian.PutUint64(inputData[32+24:], uint64(n))
|
|
||||||
binary.BigEndian.PutUint64(inputData[32+32+24:], uint64(r))
|
|
||||||
|
|
||||||
client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256,uint256,uint256)", inputData, ex)
|
testCases := []struct {
|
||||||
}
|
stackDepth int
|
||||||
|
recursionLimit int
|
||||||
|
exitCode exitcode.ExitCode
|
||||||
|
}{
|
||||||
|
{0, 1, exitcode.Ok},
|
||||||
|
{1, 1, exitcode.Ok},
|
||||||
|
{20, 1, exitcode.Ok},
|
||||||
|
{200, 1, exitcode.Ok},
|
||||||
|
{251, 1, exitcode.Ok},
|
||||||
|
{252, 1, exitCodeStackOverflow},
|
||||||
|
{0, 10, exitcode.Ok},
|
||||||
|
{1, 10, exitcode.Ok},
|
||||||
|
{20, 10, exitcode.Ok},
|
||||||
|
{200, 10, exitcode.Ok},
|
||||||
|
{251, 10, exitcode.Ok},
|
||||||
|
{252, 10, exitCodeStackOverflow},
|
||||||
|
{0, 32, exitcode.Ok},
|
||||||
|
{1, 32, exitcode.Ok},
|
||||||
|
{20, 32, exitcode.Ok},
|
||||||
|
{200, 32, exitcode.Ok},
|
||||||
|
{251, 32, exitcode.Ok},
|
||||||
|
{252, 32, exitCodeStackOverflow},
|
||||||
|
// the following are actors bundle dependent and may need to be tweaked with a network upgrade
|
||||||
|
{0, 255, exitcode.Ok},
|
||||||
|
{251, 164, exitcode.Ok},
|
||||||
|
{0, 261, exitCodeTransactionReverted},
|
||||||
|
{251, 173, exitCodeTransactionReverted},
|
||||||
}
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
var fail string
|
||||||
|
if tc.exitCode != exitcode.Ok {
|
||||||
|
fail = "-fails"
|
||||||
|
}
|
||||||
|
t.Run(fmt.Sprintf("stackDepth=%d,recursionLimit=%d%s", tc.stackDepth, tc.recursionLimit, fail), func(t *testing.T) {
|
||||||
|
inputData := make([]byte, 32*3)
|
||||||
|
binary.BigEndian.PutUint64(inputData[24:], uint64(tc.stackDepth))
|
||||||
|
binary.BigEndian.PutUint64(inputData[32+24:], uint64(tc.stackDepth))
|
||||||
|
binary.BigEndian.PutUint64(inputData[32+32+24:], uint64(tc.recursionLimit))
|
||||||
|
|
||||||
t.Run("n=0,r=1", testN(0, 1, exitcode.Ok))
|
client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256,uint256,uint256)", inputData, tc.exitCode)
|
||||||
t.Run("n=1,r=1", testN(1, 1, exitcode.Ok))
|
})
|
||||||
t.Run("n=20,r=1", testN(20, 1, exitcode.Ok))
|
}
|
||||||
t.Run("n=200,r=1", testN(200, 1, exitcode.Ok))
|
|
||||||
t.Run("n=251,r=1", testN(251, 1, exitcode.Ok))
|
|
||||||
|
|
||||||
t.Run("n=252,r=1-fails", testN(252, 1, exitcode.ExitCode(37))) // 37 means stack overflow
|
|
||||||
|
|
||||||
t.Run("n=0,r=10", testN(0, 10, exitcode.Ok))
|
|
||||||
t.Run("n=1,r=10", testN(1, 10, exitcode.Ok))
|
|
||||||
t.Run("n=20,r=10", testN(20, 10, exitcode.Ok))
|
|
||||||
t.Run("n=200,r=10", testN(200, 10, exitcode.Ok))
|
|
||||||
t.Run("n=251,r=10", testN(251, 10, exitcode.Ok))
|
|
||||||
|
|
||||||
t.Run("n=252,r=10-fails", testN(252, 10, exitcode.ExitCode(37)))
|
|
||||||
|
|
||||||
t.Run("n=0,r=32", testN(0, 32, exitcode.Ok))
|
|
||||||
t.Run("n=1,r=32", testN(1, 32, exitcode.Ok))
|
|
||||||
t.Run("n=20,r=32", testN(20, 32, exitcode.Ok))
|
|
||||||
t.Run("n=200,r=32", testN(200, 32, exitcode.Ok))
|
|
||||||
t.Run("n=251,r=32", testN(251, 32, exitcode.Ok))
|
|
||||||
|
|
||||||
t.Run("n=0,r=252", testN(0, 252, exitcode.Ok))
|
|
||||||
t.Run("n=251,r=164", testN(251, 164, exitcode.Ok))
|
|
||||||
|
|
||||||
t.Run("n=0,r=255-fails", testN(0, 255, exitcode.ExitCode(33))) // 33 means transaction reverted
|
|
||||||
t.Run("n=251,r=167-fails", testN(251, 167, exitcode.ExitCode(33)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFEVMRecursiveActorCallEstimate
|
// TestFEVMRecursiveActorCallEstimate
|
||||||
|
Loading…
Reference in New Issue
Block a user