mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
261 lines
8.5 KiB
Go
261 lines
8.5 KiB
Go
// (c) 2020-2022, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
package precompilebind
|
|
|
|
// tmplSourcePrecompileConfigGo is the Go precompiled config source template.
|
|
const tmplSourcePrecompileContractTestGo = `
|
|
// Code generated
|
|
// This file is a generated precompile contract test with the skeleton of test functions.
|
|
// The file is generated by a template. Please inspect every code and comment in this file before use.
|
|
|
|
package {{.Package}}
|
|
|
|
import (
|
|
"testing"
|
|
"math/big"
|
|
"github.com/luxfi/evm/core/state"
|
|
{{- if .Contract.AllowList}}
|
|
"github.com/luxfi/evm/precompile/allowlist"
|
|
{{- end}}
|
|
"github.com/luxfi/evm/precompile/testutils"
|
|
"github.com/luxfi/evm/vmerrs"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var (
|
|
_ = vm.ErrOutOfGas
|
|
_ = big.NewInt
|
|
_ = common.Big0
|
|
_ = require.New
|
|
)
|
|
|
|
// These tests are run against the precompile contract directly with
|
|
// the given input and expected output. They're just a guide to
|
|
// help you write your own tests. These tests are for general cases like
|
|
// allowlist, readOnly behaviour, and gas cost. You should write your own
|
|
// tests for specific cases.
|
|
var(
|
|
tests = map[string]testutils.PrecompileTest{
|
|
{{- $contract := .Contract}}
|
|
{{- $structs := .Structs}}
|
|
{{- range .Contract.Funcs}}
|
|
{{- $func := .}}
|
|
{{- if $contract.AllowList}}
|
|
{{- $roles := mkList "NoRole" "Enabled" "Manager" "Admin"}}
|
|
{{- range $role := $roles}}
|
|
{{- $fail := and (not $func.Original.IsConstant) (eq $role "NoRole")}}
|
|
"calling {{decapitalise $func.Normalized.Name}} from {{$role}} should {{- if $fail}} fail {{- else}} succeed{{- end}}": {
|
|
Caller: allowlist.Test{{$role}}Addr,
|
|
BeforeHook: allowlist.SetDefaultRoles(Module.Address),
|
|
InputFn: func(t testing.TB) []byte {
|
|
{{- if len $func.Normalized.Inputs | lt 1}}
|
|
// CUSTOM CODE STARTS HERE
|
|
// populate test input here
|
|
testInput := {{capitalise $func.Normalized.Name}}Input{}
|
|
input, err := Pack{{$func.Normalized.Name}}(testInput)
|
|
{{- else if len $func.Normalized.Inputs | eq 1 }}
|
|
{{- $input := index $func.Normalized.Inputs 0}}
|
|
// CUSTOM CODE STARTS HERE
|
|
// set test input to a value here
|
|
var testInput {{bindtype $input.Type $structs}}
|
|
testInput = {{bindtypenew $input.Type $structs}}
|
|
input, err := Pack{{$func.Normalized.Name}}(testInput)
|
|
{{- else}}
|
|
input, err := Pack{{$func.Normalized.Name}}()
|
|
{{- end}}
|
|
require.NoError(t, err)
|
|
return input
|
|
},
|
|
{{- if not $fail}}
|
|
// This test is for a successful call. You can set the expected output here.
|
|
// CUSTOM CODE STARTS HERE
|
|
ExpectedRes: func() []byte{
|
|
{{- if len $func.Normalized.Outputs | eq 0}}
|
|
// this function does not return an output, leave this one as is
|
|
packedOutput := []byte{}
|
|
{{- else}}
|
|
{{- if len $func.Normalized.Outputs | lt 1}}
|
|
var output {{capitalise $func.Normalized.Name}}Output // CUSTOM CODE FOR AN OUTPUT
|
|
{{- else }}
|
|
{{$output := index $func.Normalized.Outputs 0}}
|
|
var output {{bindtype $output.Type $structs}} // CUSTOM CODE FOR AN OUTPUT
|
|
output = {{bindtypenew $output.Type $structs}} // CUSTOM CODE FOR AN OUTPUT
|
|
{{- end}}
|
|
packedOutput, err := Pack{{$func.Normalized.Name}}Output(output)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
{{- end}}
|
|
return packedOutput
|
|
}(),
|
|
{{- end}}
|
|
SuppliedGas: {{$func.Normalized.Name}}GasCost,
|
|
ReadOnly: false,
|
|
ExpectedErr: {{if $fail}} ErrCannot{{$func.Normalized.Name}}.Error() {{- else}} "" {{- end}},
|
|
},
|
|
{{- end}}
|
|
{{- end}}
|
|
{{- if not $func.Original.IsConstant}}
|
|
"readOnly {{decapitalise $func.Normalized.Name}} should fail": {
|
|
Caller: common.Address{1},
|
|
InputFn: func(t testing.TB) []byte {
|
|
{{- if len $func.Normalized.Inputs | lt 1}}
|
|
// CUSTOM CODE STARTS HERE
|
|
// populate test input here
|
|
testInput := {{capitalise $func.Normalized.Name}}Input{}
|
|
input, err := Pack{{$func.Normalized.Name}}(testInput)
|
|
{{- else if len $func.Normalized.Inputs | eq 1 }}
|
|
{{- $input := index $func.Normalized.Inputs 0}}
|
|
// CUSTOM CODE STARTS HERE
|
|
// set test input to a value here
|
|
var testInput {{bindtype $input.Type $structs}}
|
|
testInput = {{bindtypenew $input.Type $structs}}
|
|
input, err := Pack{{$func.Normalized.Name}}(testInput)
|
|
{{- else}}
|
|
input, err := Pack{{$func.Normalized.Name}}()
|
|
{{- end}}
|
|
require.NoError(t, err)
|
|
return input
|
|
},
|
|
SuppliedGas: {{$func.Normalized.Name}}GasCost,
|
|
ReadOnly: true,
|
|
ExpectedErr: vm.ErrWriteProtection.Error(),
|
|
},
|
|
{{- end}}
|
|
"insufficient gas for {{decapitalise $func.Normalized.Name}} should fail": {
|
|
Caller: common.Address{1},
|
|
InputFn: func(t testing.TB) []byte {
|
|
{{- if len $func.Normalized.Inputs | lt 1}}
|
|
// CUSTOM CODE STARTS HERE
|
|
// populate test input here
|
|
testInput := {{capitalise $func.Normalized.Name}}Input{}
|
|
input, err := Pack{{$func.Normalized.Name}}(testInput)
|
|
{{- else if len $func.Normalized.Inputs | eq 1 }}
|
|
{{- $input := index $func.Normalized.Inputs 0}}
|
|
// CUSTOM CODE STARTS HERE
|
|
// set test input to a value here
|
|
var testInput {{bindtype $input.Type $structs}}
|
|
testInput = {{bindtypenew $input.Type $structs}}
|
|
input, err := Pack{{$func.Normalized.Name}}(testInput)
|
|
{{- else}}
|
|
input, err := Pack{{$func.Normalized.Name}}()
|
|
{{- end}}
|
|
require.NoError(t, err)
|
|
return input
|
|
},
|
|
SuppliedGas: {{$func.Normalized.Name}}GasCost - 1,
|
|
ReadOnly: false,
|
|
ExpectedErr: vm.ErrOutOfGas.Error(),
|
|
},
|
|
{{- end}}
|
|
{{- if .Contract.Fallback}}
|
|
"insufficient gas for fallback should fail": {
|
|
Caller: common.Address{1},
|
|
Input: []byte{},
|
|
SuppliedGas: {{.Contract.Type}}FallbackGasCost - 1,
|
|
ReadOnly: false,
|
|
ExpectedErr: vm.ErrOutOfGas.Error(),
|
|
},
|
|
"readOnly fallback should fail": {
|
|
Caller: common.Address{1},
|
|
Input: []byte{},
|
|
SuppliedGas: {{.Contract.Type}}FallbackGasCost,
|
|
ReadOnly: true,
|
|
ExpectedErr: vm.ErrWriteProtection.Error(),
|
|
},
|
|
"fallback should succeed": {
|
|
Caller: common.Address{1},
|
|
Input: []byte{},
|
|
SuppliedGas: {{.Contract.Type}}FallbackGasCost,
|
|
ReadOnly: false,
|
|
ExpectedErr: "",
|
|
// CUSTOM CODE STARTS HERE
|
|
// set expected output here
|
|
ExpectedRes: []byte{},
|
|
},
|
|
{{- end}}
|
|
}
|
|
)
|
|
|
|
// Test{{.Contract.Type}}Run tests the Run function of the precompile contract.
|
|
func Test{{.Contract.Type}}Run(t *testing.T) {
|
|
{{- if .Contract.AllowList}}
|
|
// Run tests with allowlist tests.
|
|
// This adds allowlist tests to your custom tests
|
|
// and runs them all together.
|
|
// Even if you don't add any custom tests, keep this. This will still
|
|
// run the default allowlist tests.
|
|
allowlist.RunPrecompileWithAllowListTests(t, Module, extstate.NewTestStateDB, tests)
|
|
{{- else}}
|
|
// Run tests.
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
test.Run(t, Module, extstate.NewTestStateDB(t))
|
|
})
|
|
}
|
|
{{- end}}
|
|
}
|
|
|
|
{{range .Contract.Events}}
|
|
{{$hasData := false}}
|
|
{{range .Normalized.Inputs}}
|
|
{{ if not .Indexed}}
|
|
{{ $hasData = true}}
|
|
{{end}}
|
|
{{end}}
|
|
{{ if $hasData}}
|
|
// TestPackUnpack{{.Normalized.Name}}EventData tests the Pack/Unpack{{.Normalized.Name}}EventData.
|
|
func TestPackUnpack{{.Normalized.Name}}EventData(t *testing.T) {
|
|
// CUSTOM CODE STARTS HERE
|
|
// set test inputs with proper values here
|
|
{{- range .Normalized.Inputs}}
|
|
{{if .Indexed}}var {{decapitalise .Name}}Input {{bindtype .Type $structs}} = {{bindtypenew .Type $structs}}{{end}}
|
|
{{- end}}
|
|
{{if $hasData}} dataInput := {{.Normalized.Name}}EventData{{end}}{
|
|
{{- range .Normalized.Inputs}}
|
|
{{- if not .Indexed}}
|
|
{{capitalise .Name}}: {{bindtypenew .Type $structs}},
|
|
{{- end}}
|
|
{{- end}}
|
|
}
|
|
|
|
_, data, err := Pack{{.Normalized.Name}}Event(
|
|
{{- range .Normalized.Inputs}}
|
|
{{- if .Indexed}}
|
|
{{decapitalise .Name}}Input,
|
|
{{- end}}
|
|
{{- end}}
|
|
{{- if $hasData}}
|
|
dataInput,
|
|
{{- end}}
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
unpacked, err := Unpack{{.Normalized.Name}}EventData(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, dataInput, unpacked)
|
|
}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
func Benchmark{{.Contract.Type}}(b *testing.B) {
|
|
{{- if .Contract.AllowList}}
|
|
// Benchmark tests with allowlist tests.
|
|
// This adds allowlist tests to your custom tests
|
|
// and benchmarks them all together.
|
|
// Even if you don't add any custom tests, keep this. This will still
|
|
// run the default allowlist tests.
|
|
allowlist.BenchPrecompileWithAllowList(b, Module, extstate.NewTestStateDB, tests)
|
|
{{- else}}
|
|
// Benchmark tests.
|
|
for name, test := range tests {
|
|
b.Run(name, func(b *testing.B) {
|
|
test.Bench(b, Module, extstate.NewTestStateDB(b))
|
|
})
|
|
}
|
|
{{- end}}
|
|
}
|
|
|
|
`
|