From ef8d01223c07befcaf627fd707ca0da5322f6dc6 Mon Sep 17 00:00:00 2001 From: Arkadiy Kukarkin Date: Fri, 10 Apr 2026 18:01:47 +0200 Subject: [PATCH] add FVM mock precompile helpers for Anvil integration tests Deploy mock Filecoin precompiles (from fvm-solidity) at their canonical 0xFE00... addresses via anvil_setCode. This lets contracts that call RESOLVE_ADDRESS, CALL_ACTOR_BY_ID, etc. get working responses on Anvil forks instead of reverting on empty addresses. - SetupFVMPrecompiles(t, rpcURL): deploys all 3 mock precompiles - RegisterActorID(t, rpcURL, evmAddr, actorID): registers address->actor mapping - Vendored compiled bytecodes from fvm-solidity mocks (FVMActor, FVMCallActorById, FVMCallActorByAddress) - Integration tests verifying deployment and address resolution --- .../fvm_call_actor_by_address_bytecode.txt | 1 + .../fvm_call_actor_by_id_bytecode.txt | 1 + util/testutil/fvm_precompiles.go | 83 ++++++++++++++ util/testutil/fvm_precompiles_test.go | 104 ++++++++++++++++++ .../testutil/fvm_resolve_address_bytecode.txt | 1 + 5 files changed, 190 insertions(+) create mode 100644 util/testutil/fvm_call_actor_by_address_bytecode.txt create mode 100644 util/testutil/fvm_call_actor_by_id_bytecode.txt create mode 100644 util/testutil/fvm_precompiles.go create mode 100644 util/testutil/fvm_precompiles_test.go create mode 100644 util/testutil/fvm_resolve_address_bytecode.txt diff --git a/util/testutil/fvm_call_actor_by_address_bytecode.txt b/util/testutil/fvm_call_actor_by_address_bytecode.txt new file mode 100644 index 00000000..b5a68296 --- /dev/null +++ b/util/testutil/fvm_call_actor_by_address_bytecode.txt @@ -0,0 +1 @@ +0x60806040525f5f5f5f5f5f5f3681019061001991906105c8565b9550955095509550955095506002815111610069576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161006090610709565b60405180910390fd5b600460f81b815f8151811061008157610080610727565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146100ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e5906107c4565b60405180910390fd5b600a60f81b8160018151811061010757610106610727565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161016b90610852565b60405180910390fd5b60168151146101b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101af906108e0565b60405180910390fd5b5f67ffffffffffffffff168667ffffffffffffffff161461020e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102059061096e565b60405180910390fd5b5f67ffffffffffffffff168467ffffffffffffffff1614610264576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161025b906109fc565b60405180910390fd5b5f67ffffffffffffffff168367ffffffffffffffff16146102ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b190610a8a565b60405180910390fd5b5f8251146102fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102f490610b18565b60405180910390fd5b5f816016015190505f8173ffffffffffffffffffffffffffffffffffffffff168760405161032a90610b63565b5f6040518083038185875af1925050503d805f8114610364576040519150601f19603f3d011682016040523d82523d5f602084013e610369565b606091505b50509050606081156103ae575f5f60405180602001604052805f81525060405160200161039893929190610bfe565b6040516020818303038152906040529050610403565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5f60405180602001604052805f8152506040516020016103f193929190610bfe565b60405160208183030381529060405290505b805160208201f35b5f604051905090565b5f5ffd5b5f5ffd5b5f67ffffffffffffffff82169050919050565b6104388161041c565b8114610442575f5ffd5b50565b5f813590506104538161042f565b92915050565b5f819050919050565b61046b81610459565b8114610475575f5ffd5b50565b5f8135905061048681610462565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6104da82610494565b810181811067ffffffffffffffff821117156104f9576104f86104a4565b5b80604052505050565b5f61050b61040b565b905061051782826104d1565b919050565b5f67ffffffffffffffff821115610536576105356104a4565b5b61053f82610494565b9050602081019050919050565b828183375f83830152505050565b5f61056c6105678461051c565b610502565b90508281526020810184848401111561058857610587610490565b5b61059384828561054c565b509392505050565b5f82601f8301126105af576105ae61048c565b5b81356105bf84826020860161055a565b91505092915050565b5f5f5f5f5f5f60c087890312156105e2576105e1610414565b5b5f6105ef89828a01610445565b965050602061060089828a01610478565b955050604061061189828a01610445565b945050606061062289828a01610445565b935050608087013567ffffffffffffffff81111561064357610642610418565b5b61064f89828a0161059b565b92505060a087013567ffffffffffffffff8111156106705761066f610418565b5b61067c89828a0161059b565b9150509295509295509295565b5f82825260208201905092915050565b7f46564d43616c6c4163746f724279416464726573733a20496e76616c696420735f8201527f686f727420616464726573730000000000000000000000000000000000000000602082015250565b5f6106f3602c83610689565b91506106fe82610699565b604082019050919050565b5f6020820190508181035f830152610720816106e7565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f46564d43616c6c4163746f724279416464726573733a204f6e6c7920663420615f8201527f646472657373657320737570706f727465640000000000000000000000000000602082015250565b5f6107ae603283610689565b91506107b982610754565b604082019050919050565b5f6020820190508181035f8301526107db816107a2565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c7920663431305f8201527f2061646472657373657320737570706f72746564000000000000000000000000602082015250565b5f61083c603483610689565b9150610847826107e2565b604082019050919050565b5f6020820190508181035f83015261086981610830565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a20496e76616c696420665f8201527f3431302061646472657373206c656e6774680000000000000000000000000000602082015250565b5f6108ca603283610689565b91506108d582610870565b604082019050919050565b5f6020820190508181035f8301526108f7816108be565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c79206d6574685f8201527f6f642030202873656e642920737570706f727465640000000000000000000000602082015250565b5f610958603583610689565b9150610963826108fe565b604082019050919050565b5f6020820190508181035f8301526109858161094c565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c79206e6f6e2d5f8201527f726561646f6e6c792063616c6c7320737570706f727465640000000000000000602082015250565b5f6109e6603883610689565b91506109f18261098c565b604082019050919050565b5f6020820190508181035f830152610a13816109da565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204f6e6c79206e6f2d635f8201527f6f6465632063616c6c7320737570706f72746564000000000000000000000000602082015250565b5f610a74603483610689565b9150610a7f82610a1a565b604082019050919050565b5f6020820190508181035f830152610aa181610a68565b9050919050565b7f46564d43616c6c4163746f724279416464726573733a204e6f20706172616d735f8201527f2065787065637465640000000000000000000000000000000000000000000000602082015250565b5f610b02602983610689565b9150610b0d82610aa8565b604082019050919050565b5f6020820190508181035f830152610b2f81610af6565b9050919050565b5f81905092915050565b50565b5f610b4e5f83610b36565b9150610b5982610b40565b5f82019050919050565b5f610b6d82610b43565b9150819050919050565b5f819050919050565b610b8981610b77565b82525050565b610b988161041c565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f610bd082610b9e565b610bda8185610ba8565b9350610bea818560208601610bb8565b610bf381610494565b840191505092915050565b5f606082019050610c115f830186610b80565b610c1e6020830185610b8f565b8181036040830152610c308184610bc6565b905094935050505056fea2646970667358221220f1098bf2d0d55cf798988475faf22c2d74b959957bae4fca1e77ac1a7c9b6a0264736f6c63430008210033 diff --git a/util/testutil/fvm_call_actor_by_id_bytecode.txt b/util/testutil/fvm_call_actor_by_id_bytecode.txt new file mode 100644 index 00000000..8e25e6a4 --- /dev/null +++ b/util/testutil/fvm_call_actor_by_id_bytecode.txt @@ -0,0 +1 @@ +0x60806040525f5f5f5f5f5f5f368101906100199190610498565b955095509550955095509550606367ffffffffffffffff168167ffffffffffffffff161461007c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610073906105bd565b60405180910390fd5b5f67ffffffffffffffff168667ffffffffffffffff16146100d2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100c99061064b565b60405180910390fd5b5f67ffffffffffffffff168467ffffffffffffffff1614610128576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161011f906106d9565b60405180910390fd5b5f67ffffffffffffffff168367ffffffffffffffff161461017e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017590610767565b60405180910390fd5b5f8251146101c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101b8906107f5565b60405180910390fd5b5f73ff0000000000000000000000000000000000006373ffffffffffffffffffffffffffffffffffffffff16866040516101fa90610840565b5f6040518083038185875af1925050503d805f8114610234576040519150601f19603f3d011682016040523d82523d5f602084013e610239565b606091505b505090506060811561027e575f5f60405180602001604052805f815250604051602001610268939291906108db565b60405160208183030381529060405290506102d3565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5f60405180602001604052805f8152506040516020016102c1939291906108db565b60405160208183030381529060405290505b805160208201f35b5f604051905090565b5f5ffd5b5f5ffd5b5f67ffffffffffffffff82169050919050565b610308816102ec565b8114610312575f5ffd5b50565b5f81359050610323816102ff565b92915050565b5f819050919050565b61033b81610329565b8114610345575f5ffd5b50565b5f8135905061035681610332565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103aa82610364565b810181811067ffffffffffffffff821117156103c9576103c8610374565b5b80604052505050565b5f6103db6102db565b90506103e782826103a1565b919050565b5f67ffffffffffffffff82111561040657610405610374565b5b61040f82610364565b9050602081019050919050565b828183375f83830152505050565b5f61043c610437846103ec565b6103d2565b90508281526020810184848401111561045857610457610360565b5b61046384828561041c565b509392505050565b5f82601f83011261047f5761047e61035c565b5b813561048f84826020860161042a565b91505092915050565b5f5f5f5f5f5f60c087890312156104b2576104b16102e4565b5b5f6104bf89828a01610315565b96505060206104d089828a01610348565b95505060406104e189828a01610315565b94505060606104f289828a01610315565b935050608087013567ffffffffffffffff811115610513576105126102e8565b5b61051f89828a0161046b565b92505060a061053089828a01610315565b9150509295509295509295565b5f82825260208201905092915050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206275726e206163746f5f8201527f72202839392920737570706f7274656400000000000000000000000000000000602082015250565b5f6105a760308361053d565b91506105b28261054d565b604082019050919050565b5f6020820190508181035f8301526105d48161059b565b9050919050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206d6574686f642030205f8201527f2873656e642920737570706f7274656400000000000000000000000000000000602082015250565b5f61063560308361053d565b9150610640826105db565b604082019050919050565b5f6020820190508181035f83015261066281610629565b9050919050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206e6f6e2d726561646f5f8201527f6e6c792063616c6c7320737570706f7274656400000000000000000000000000602082015250565b5f6106c360338361053d565b91506106ce82610669565b604082019050919050565b5f6020820190508181035f8301526106f0816106b7565b9050919050565b7f46564d43616c6c4163746f72427949643a204f6e6c79206e6f2d636f646563205f8201527f63616c6c7320737570706f727465640000000000000000000000000000000000602082015250565b5f610751602f8361053d565b915061075c826106f7565b604082019050919050565b5f6020820190508181035f83015261077e81610745565b9050919050565b7f46564d43616c6c4163746f72427949643a204e6f20706172616d7320657870655f8201527f6374656400000000000000000000000000000000000000000000000000000000602082015250565b5f6107df60248361053d565b91506107ea82610785565b604082019050919050565b5f6020820190508181035f83015261080c816107d3565b9050919050565b5f81905092915050565b50565b5f61082b5f83610813565b91506108368261081d565b5f82019050919050565b5f61084a82610820565b9150819050919050565b5f819050919050565b61086681610854565b82525050565b610875816102ec565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6108ad8261087b565b6108b78185610885565b93506108c7818560208601610895565b6108d081610364565b840191505092915050565b5f6060820190506108ee5f83018661085d565b6108fb602083018561086c565b818103604083015261090d81846108a3565b905094935050505056fea2646970667358221220c8c1249609242f6af584fc1ec1558364b1d4c5fff1a3012b2dc5a3ee4e4e7cf264736f6c63430008210033 diff --git a/util/testutil/fvm_precompiles.go b/util/testutil/fvm_precompiles.go new file mode 100644 index 00000000..2c4b2d8a --- /dev/null +++ b/util/testutil/fvm_precompiles.go @@ -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 +} diff --git a/util/testutil/fvm_precompiles_test.go b/util/testutil/fvm_precompiles_test.go new file mode 100644 index 00000000..3b6e31f6 --- /dev/null +++ b/util/testutil/fvm_precompiles_test.go @@ -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") +} diff --git a/util/testutil/fvm_resolve_address_bytecode.txt b/util/testutil/fvm_resolve_address_bytecode.txt new file mode 100644 index 00000000..1d0e20db --- /dev/null +++ b/util/testutil/fvm_resolve_address_bytecode.txt @@ -0,0 +1 @@ +0x608060405234801561000f575f5ffd5b5060043610610043575f3560e01c806365e12deb146101dc5780637ee5d3a2146101f8578063f4f5ef1f1461022857610044565b5b5f5f368080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505f8151116100ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100c59061036d565b60405180910390fd5b5f815f815181106100e2576100e161038b565b5b602001015160f81c60f81b60f81c905060048160ff161115610139576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161013090610428565b60405180910390fd5b5f8251602084012090505f5f5f8381526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f8167ffffffffffffffff1611806101a157507f54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d5679882145b156101da575f8167ffffffffffffffff166040516020016101c2919061045e565b60405160208183030381529060405290506020808201f35b005b6101f660048036038101906101f1919061051f565b610244565b005b610212600480360381019061020d9190610590565b6102af565b60405161021f91906105ca565b60405180910390f35b610242600480360381019061023d919061071f565b6102d2565b005b5f6004600a8460405160200161025c939291906107fe565b6040516020818303038152906040529050815f5f838051906020012081526020019081526020015f205f6101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b5f602052805f5260405f205f915054906101000a900467ffffffffffffffff1681565b805f5f848051906020012081526020019081526020015f205f6101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505050565b5f82825260208201905092915050565b7f496e76616c696420616464726573733a2020656d7074790000000000000000005f82015250565b5f610357601783610313565b915061036282610323565b602082019050919050565b5f6020820190508181035f8301526103848161034b565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f496e76616c696420616464726573733a20756e6b6e6f776e2070726f746f636f5f8201527f6c00000000000000000000000000000000000000000000000000000000000000602082015250565b5f610412602183610313565b915061041d826103b8565b604082019050919050565b5f6020820190508181035f83015261043f81610406565b9050919050565b5f819050919050565b61045881610446565b82525050565b5f6020820190506104715f83018461044f565b92915050565b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6104b182610488565b9050919050565b6104c1816104a7565b81146104cb575f5ffd5b50565b5f813590506104dc816104b8565b92915050565b5f67ffffffffffffffff82169050919050565b6104fe816104e2565b8114610508575f5ffd5b50565b5f81359050610519816104f5565b92915050565b5f5f6040838503121561053557610534610480565b5b5f610542858286016104ce565b92505060206105538582860161050b565b9150509250929050565b5f819050919050565b61056f8161055d565b8114610579575f5ffd5b50565b5f8135905061058a81610566565b92915050565b5f602082840312156105a5576105a4610480565b5b5f6105b28482850161057c565b91505092915050565b6105c4816104e2565b82525050565b5f6020820190506105dd5f8301846105bb565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610631826105eb565b810181811067ffffffffffffffff821117156106505761064f6105fb565b5b80604052505050565b5f610662610477565b905061066e8282610628565b919050565b5f67ffffffffffffffff82111561068d5761068c6105fb565b5b610696826105eb565b9050602081019050919050565b828183375f83830152505050565b5f6106c36106be84610673565b610659565b9050828152602081018484840111156106df576106de6105e7565b5b6106ea8482856106a3565b509392505050565b5f82601f830112610706576107056105e3565b5b81356107168482602086016106b1565b91505092915050565b5f5f6040838503121561073557610734610480565b5b5f83013567ffffffffffffffff81111561075257610751610484565b5b61075e858286016106f2565b925050602061076f8582860161050b565b9150509250929050565b5f60ff82169050919050565b5f8160f81b9050919050565b5f61079b82610785565b9050919050565b6107b36107ae82610779565b610791565b82525050565b5f8160601b9050919050565b5f6107cf826107b9565b9050919050565b5f6107e0826107c5565b9050919050565b6107f86107f3826104a7565b6107d6565b82525050565b5f61080982866107a2565b60018201915061081982856107a2565b60018201915061082982846107e7565b60148201915081905094935050505056fea26469706673582212205873f3cd2efb705b4ddbd8f8ddb9375e27a047c7553413f61c95c625ff2ae61564736f6c63430008210033