Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions util/testutil/fvm_call_actor_by_address_bytecode.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x60806040525f5f5f5f5f5f5f3681019061001991906105c8565b9550955095509550955095506002815111610069576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161006090610709565b60405180910390fd5b600460f81b815f8151811061008157610080610727565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146100ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e5906107c4565b60405180910390fd5b600a60f81b8160018151811061010757610106610727565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016b90610852565b60405180910390fd5b60168151146101b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101af906108e0565b60405180910390fd5b5f67ffffffffffffffff168667ffffffffffffffff161461020e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102059061096e565b60405180910390fd5b5f67ffffffffffffffff168467ffffffffffffffff1614610264576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161025b906109fc565b60405180910390fd5b5f67ffffffffffffffff168367ffffffffffffffff16146102ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b190610a8a565b60405180910390fd5b5f8251146102fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102f490610b18565b60405180910390fd5b5f816016015190505f8173ffffffffffffffffffffffffffffffffffffffff168760405161032a90610b63565b5f6040518083038185875af1925050503d805f8114610364576040519150601f19603f3d011682016040523d82523d5f602084013e610369565b606091505b50509050606081156103ae575f5f60405180602001604052805f81525060405160200161039893929190610bfe565b6040516020818303038152906040529050610403565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5f60405180602001604052805f8152506040516020016103f193929190610bfe565b60405160208183030381529060405290505b805160208201f35b5f604051905090565b5f5ffd5b5f5ffd5b5f67ffffffffffffffff82169050919050565b6104388161041c565b8114610442575f5ffd5b50565b5f813590506104538161042f565b92915050565b5f819050919050565b61046b81610459565b8114610475575f5ffd5b50565b5f8135905061048681610462565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6104da82610494565b810181811067ffffffffffffffff821117156104f9576104f86104a4565b5b80604052505050565b5f61050b61040b565b905061051782826104d1565b919050565b5f67ffffffffffffffff821115610536576105356104a4565b5b61053f82610494565b9050602081019050919050565b828183375f83830152505050565b5f61056c6105678461051c565b610502565b90508281526020810184848401111561058857610587610490565b5b61059384828561054c565b509392505050565b5f82601f8301126105af576105ae61048c565b5b81356105bf84826020860161055a565b91505092915050565b5f5f5f5f5f5f60c087890312156105e2576105e1610414565b5b5f6105ef89828a01610445565b965050602061060089828a01610478565b955050604061061189828a01610445565b945050606061062289828a01610445565b935050608087013567ffffffffffffffff81111561064357610642610418565b5b61064f89828a0161059b565b92505060a087013567ffffffffffffffff8111156106705761066f610418565b5b61067c89828a0161059b565b9150509295509295509295565b5f82825260208201905092915050565b7f46564d43616c6c4163746f724279416464726573733a20496e76616c696420735f8201527f686f727420616464726573730000000000000000000000000000000000000000602082015250565b5f6106f3602c83610689565b91506106fe82610699565b604082019050919050565b5f6020820190508181035f830152610720816106e7565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f46564d43616c6c4163746f724279416464726573733a204f6e6c7920663420615f8201527f646472657373657320737570706f727465640000000000000000000000000000602082015250565b5f6107ae603283610689565b91506107b982610754565b604082019050919050565b5f6020820190508181035f8301526107db816107a2565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c7920663431305f8201527f2061646472657373657320737570706f72746564000000000000000000000000602082015250565b5f61083c603483610689565b9150610847826107e2565b604082019050919050565b5f6020820190508181035f83015261086981610830565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a20496e76616c696420665f8201527f3431302061646472657373206c656e6774680000000000000000000000000000602082015250565b5f6108ca603283610689565b91506108d582610870565b604082019050919050565b5f6020820190508181035f8301526108f7816108be565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c79206d6574685f8201527f6f642030202873656e642920737570706f727465640000000000000000000000602082015250565b5f610958603583610689565b9150610963826108fe565b604082019050919050565b5f6020820190508181035f8301526109858161094c565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c79206e6f6e2d5f8201527f726561646f6e6c792063616c6c7320737570706f727465640000000000000000602082015250565b5f6109e6603883610689565b91506109f18261098c565b604082019050919050565b5f6020820190508181035f830152610a13816109da565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c79206e6f2d635f8201527f6f6465632063616c6c7320737570706f72746564000000000000000000000000602082015250565b5f610a74603483610689565b9150610a7f82610a1a565b604082019050919050565b5f6020820190508181035f830152610aa181610a68565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204e6f20706172616d735f8201527f2065787065637465640000000000000000000000000000000000000000000000602082015250565b5f610b02602983610689565b9150610b0d82610aa8565b604082019050919050565b5f6020820190508181035f830152610b2f81610af6565b9050919050565b5f81905092915050565b50565b5f610b4e5f83610b36565b9150610b5982610b40565b5f82019050919050565b5f610b6d82610b43565b9150819050919050565b5f819050919050565b610b8981610b77565b82525050565b610b988161041c565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f610bd082610b9e565b610bda8185610ba8565b9350610bea818560208601610bb8565b610bf381610494565b840191505092915050565b5f606082019050610c115f830186610b80565b610c1e6020830185610b8f565b8181036040830152610c308184610bc6565b905094935050505056fea2646970667358221220f1098bf2d0d55cf798988475faf22c2d74b959957bae4fca1e77ac1a7c9b6a0264736f6c63430008210033
1 change: 1 addition & 0 deletions util/testutil/fvm_call_actor_by_id_bytecode.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x60806040525f5f5f5f5f5f5f368101906100199190610498565b955095509550955095509550606367ffffffffffffffff168167ffffffffffffffff161461007c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610073906105bd565b60405180910390fd5b5f67ffffffffffffffff168667ffffffffffffffff16146100d2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100c99061064b565b60405180910390fd5b5f67ffffffffffffffff168467ffffffffffffffff1614610128576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161011f906106d9565b60405180910390fd5b5f67ffffffffffffffff168367ffffffffffffffff161461017e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017590610767565b60405180910390fd5b5f8251146101c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101b8906107f5565b60405180910390fd5b5f73ff0000000000000000000000000000000000006373ffffffffffffffffffffffffffffffffffffffff16866040516101fa90610840565b5f6040518083038185875af1925050503d805f8114610234576040519150601f19603f3d011682016040523d82523d5f602084013e610239565b606091505b505090506060811561027e575f5f60405180602001604052805f815250604051602001610268939291906108db565b60405160208183030381529060405290506102d3565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5f60405180602001604052805f8152506040516020016102c1939291906108db565b60405160208183030381529060405290505b805160208201f35b5f604051905090565b5f5ffd5b5f5ffd5b5f67ffffffffffffffff82169050919050565b610308816102ec565b8114610312575f5ffd5b50565b5f81359050610323816102ff565b92915050565b5f819050919050565b61033b81610329565b8114610345575f5ffd5b50565b5f8135905061035681610332565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103aa82610364565b810181811067ffffffffffffffff821117156103c9576103c8610374565b5b80604052505050565b5f6103db6102db565b90506103e782826103a1565b919050565b5f67ffffffffffffffff82111561040657610405610374565b5b61040f82610364565b9050602081019050919050565b828183375f83830152505050565b5f61043c610437846103ec565b6103d2565b90508281526020810184848401111561045857610457610360565b5b61046384828561041c565b509392505050565b5f82601f83011261047f5761047e61035c565b5b813561048f84826020860161042a565b91505092915050565b5f5f5f5f5f5f60c087890312156104b2576104b16102e4565b5b5f6104bf89828a01610315565b96505060206104d089828a01610348565b95505060406104e189828a01610315565b94505060606104f289828a01610315565b935050608087013567ffffffffffffffff811115610513576105126102e8565b5b61051f89828a0161046b565b92505060a061053089828a01610315565b9150509295509295509295565b5f82825260208201905092915050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206275726e206163746f5f8201527f72202839392920737570706f7274656400000000000000000000000000000000602082015250565b5f6105a760308361053d565b91506105b28261054d565b604082019050919050565b5f6020820190508181035f8301526105d48161059b565b9050919050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206d6574686f642030205f8201527f2873656e642920737570706f7274656400000000000000000000000000000000602082015250565b5f61063560308361053d565b9150610640826105db565b604082019050919050565b5f6020820190508181035f83015261066281610629565b9050919050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206e6f6e2d726561646f5f8201527f6e6c792063616c6c7320737570706f7274656400000000000000000000000000602082015250565b5f6106c360338361053d565b91506106ce82610669565b604082019050919050565b5f6020820190508181035f8301526106f0816106b7565b9050919050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206e6f2d636f646563205f8201527f63616c6c7320737570706f727465640000000000000000000000000000000000602082015250565b5f610751602f8361053d565b915061075c826106f7565b604082019050919050565b5f6020820190508181035f83015261077e81610745565b9050919050565b7f46564d43616c6c4163746f72427949643a204e6f20706172616d7320657870655f8201527f6374656400000000000000000000000000000000000000000000000000000000602082015250565b5f6107df60248361053d565b91506107ea82610785565b604082019050919050565b5f6020820190508181035f83015261080c816107d3565b9050919050565b5f81905092915050565b50565b5f61082b5f83610813565b91506108368261081d565b5f82019050919050565b5f61084a82610820565b9150819050919050565b5f819050919050565b61086681610854565b82525050565b610875816102ec565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6108ad8261087b565b6108b78185610885565b93506108c7818560208601610895565b6108d081610364565b840191505092915050565b5f6060820190506108ee5f83018661085d565b6108fb602083018561086c565b818103604083015261090d81846108a3565b905094935050505056fea2646970667358221220c8c1249609242f6af584fc1ec1558364b1d4c5fff1a3012b2dc5a3ee4e4e7cf264736f6c63430008210033
83 changes: 83 additions & 0 deletions util/testutil/fvm_precompiles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package testutil

import (
_ "embed"
"encoding/binary"
"encoding/hex"
"strings"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)

//go:embed fvm_resolve_address_bytecode.txt
var fvmResolveAddressBytecode string

//go:embed fvm_call_actor_by_id_bytecode.txt
var fvmCallActorByIDBytecode string

//go:embed fvm_call_actor_by_address_bytecode.txt
var fvmCallActorByAddressBytecode string

var (
// canonical Filecoin precompile addresses
FVMResolveAddress = common.HexToAddress("0xFE00000000000000000000000000000000000001")
FVMCallActorByAddress = common.HexToAddress("0xfe00000000000000000000000000000000000003")
FVMCallActorByID = common.HexToAddress("0xfe00000000000000000000000000000000000005")
)

// SetupFVMPrecompiles deploys mock Filecoin precompiles on an Anvil fork
// using anvil_setCode. Contracts that call RESOLVE_ADDRESS, CALL_ACTOR_BY_ID,
// etc. get working mock responses instead of reverting on empty addresses.
//
// Mock bytecodes are from github.com/filecoin-project/fvm-solidity/src/mocks/.
// After calling this, use RegisterActorID to map EVM addresses to f0 actor IDs.
func SetupFVMPrecompiles(t *testing.T, rpcURL string) {
t.Helper()
anvilSetCode(t, rpcURL, FVMResolveAddress, mustDecodeHex(t, fvmResolveAddressBytecode))
anvilSetCode(t, rpcURL, FVMCallActorByID, mustDecodeHex(t, fvmCallActorByIDBytecode))
anvilSetCode(t, rpcURL, FVMCallActorByAddress, mustDecodeHex(t, fvmCallActorByAddressBytecode))
t.Log("FVM mock precompiles deployed")
}

// RegisterActorID maps an EVM address to a Filecoin actor ID in the mock
// RESOLVE_ADDRESS precompile. The EVM address is encoded as an f410
// delegated address (protocol 0x04, namespace 0x0a = EAM, 20-byte addr).
func RegisterActorID(t *testing.T, rpcURL string, evmAddr common.Address, actorID uint64) {
t.Helper()

// f410 encoding: 0x04 (protocol 4, delegated) + 0x0a (namespace 10, EAM) + 20 bytes
filAddr := make([]byte, 22)
filAddr[0] = 0x04
filAddr[1] = 0x0a
copy(filAddr[2:], evmAddr.Bytes())

// ABI encode mockResolveAddress(bytes,uint64)
selector := crypto.Keccak256([]byte("mockResolveAddress(bytes,uint64)"))[:4]
data := make([]byte, 4+32+32+32+32) // selector + offset + actorID + len + data
copy(data[0:4], selector)
data[4+31] = 64 // offset to bytes param
binary.BigEndian.PutUint64(data[4+32+24:4+32+32], actorID) // uint64 actorID
data[4+64+31] = 22 // bytes length
copy(data[4+96:4+96+22], filAddr) // bytes data

funderAddr := common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
AnvilImpersonate(t, rpcURL, funderAddr)
SendImpersonatedTx(t, rpcURL, funderAddr, FVMResolveAddress, data)
t.Logf("registered actor ID %d for %s", actorID, evmAddr.Hex())
}

func anvilSetCode(t *testing.T, rpcURL string, addr common.Address, code []byte) {
t.Helper()
anvilRPC(t, rpcURL, "anvil_setCode", []any{addr.Hex(), "0x" + hex.EncodeToString(code)})
}

func mustDecodeHex(t *testing.T, s string) []byte {
t.Helper()
s = strings.TrimPrefix(strings.TrimSpace(s), "0x")
b, err := hex.DecodeString(s)
require.NoError(t, err, "failed to decode hex bytecode")
return b
}
104 changes: 104 additions & 0 deletions util/testutil/fvm_precompiles_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package testutil

import (
"context"
"testing"
"time"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require"
)

// TestIntegration_FVMPrecompiles verifies that mock precompiles can be
// deployed via anvil_setCode and that RESOLVE_ADDRESS responds to
// registered actor IDs.
func TestIntegration_FVMPrecompiles(t *testing.T) {
anvil := StartAnvil(t, CalibnetRPC)

SetupFVMPrecompiles(t, anvil.RPCURL)

// register anvil account 0 as actor t05103 (its real calibnet actor ID)
account0 := common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
RegisterActorID(t, anvil.RPCURL, account0, 5103)

// verify the precompile resolves the address
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

client, err := ethclient.DialContext(ctx, anvil.RPCURL)
require.NoError(t, err)
defer client.Close()

// call RESOLVE_ADDRESS with account0's f410 encoding
filAddr := make([]byte, 22)
filAddr[0] = 0x04
filAddr[1] = 0x0a
copy(filAddr[2:], account0.Bytes())

// the precompile's fallback expects raw bytes (the filecoin address)
result, err := client.CallContract(ctx, ethereum.CallMsg{
To: &FVMResolveAddress,
Data: filAddr,
}, nil)
require.NoError(t, err)
require.GreaterOrEqual(t, len(result), 8, "expected at least 8 bytes for uint64 actor ID")
t.Logf("RESOLVE_ADDRESS returned %d bytes: 0x%x", len(result), result)

// also verify code exists at the precompile addresses
for name, addr := range map[string]common.Address{
"RESOLVE_ADDRESS": FVMResolveAddress,
"CALL_ACTOR_BY_ID": FVMCallActorByID,
"CALL_ACTOR_BY_ADDRESS": FVMCallActorByAddress,
} {
code, err := client.CodeAt(ctx, addr, nil)
require.NoError(t, err)
require.NotEmpty(t, code, "%s should have code deployed", name)
t.Logf("%s: %d bytes of code", name, len(code))
}
}

// TestIntegration_FVMPrecompileUnregisteredAddress verifies that the mock
// RESOLVE_ADDRESS precompile reverts for addresses that haven't been
// registered, matching the real precompile behavior.
func TestIntegration_FVMPrecompileUnregisteredAddress(t *testing.T) {
anvil := StartAnvil(t, CalibnetRPC)

SetupFVMPrecompiles(t, anvil.RPCURL)

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

client, err := ethclient.DialContext(ctx, anvil.RPCURL)
require.NoError(t, err)
defer client.Close()

// generate a random address that hasn't been registered
key, err := crypto.GenerateKey()
require.NoError(t, err)
unregistered := crypto.PubkeyToAddress(key.PublicKey)

filAddr := make([]byte, 22)
filAddr[0] = 0x04
filAddr[1] = 0x0a
copy(filAddr[2:], unregistered.Bytes())

// the mock returns 0 for unregistered addresses (no revert)
result, err := client.CallContract(ctx, ethereum.CallMsg{
To: &FVMResolveAddress,
Data: filAddr,
}, nil)
require.NoError(t, err)
// all bytes should be zero (actor ID 0 = not found)
allZero := true
for _, b := range result {
if b != 0 {
allZero = false
break
}
}
require.True(t, allZero, "unregistered address should resolve to actor ID 0")
t.Logf("unregistered address correctly resolved to 0")
}
Loading
Loading