feat: api: improve the correctness of Eth's trace_block (#11609)

* Improve the correctness of Eth's trace_block

- Improve encoding/decoding of parameters and return values:
  - Encode "native" parameters and return values with Solidity ABI.
  - Correctly decode parameters to "create" calls.
  - Use the correct (ish) output for "create" calls.
  - Handle all forms of "create".
- Make robust with respect to reverts:
  - Use the actor ID/address from the trace instead of looking it up in
    the state-tree (may not exist in the state-tree due to a revert).
  - Gracefully handle failed actor/contract creation.
- Improve performance:
  - We avoid looking anything up in the state-tree when translating the
    trace, which should significantly improve performance.
- Improve code readability:
  - Remove all "backtracking" logic.
  - Use an "environment" struct to store temporary state instead of
    attaching it to the trace.
- Fix random bugs:
  - Fix an allocation bug in the "address" logic (need to set the
    capacity before modifying the slice).
  - Improved error checking/handling.
- Use correct types for `trace_block` action/results (create, call, etc.).
  - And use the correct types for Result/Action structs instead of reusing the same "Call" action every time.
- Improve error messages.
This commit is contained in:
Steven Allen
2024-02-21 12:20:00 -08:00
committed by GitHub
parent 01cfe8fc72
commit 8ba491b6b4
14 changed files with 809 additions and 601 deletions
+17 -16
View File
@@ -382,34 +382,35 @@ func parseEthRevert(ret []byte) string {
// 3. Otherwise, we fall back to returning a masked ID Ethereum address. If the supplied address is an f0 address, we
// use that ID to form the masked ID address.
// 4. Otherwise, we fetch the actor's ID from the state tree and form the masked ID with it.
//
// If the actor doesn't exist in the state-tree but we have its ID, we use a masked ID address. It could have been deleted.
func lookupEthAddress(addr address.Address, st *state.StateTree) (ethtypes.EthAddress, error) {
// BLOCK A: We are trying to get an actual Ethereum address from an f410 address.
// Attempt to convert directly, if it's an f4 address.
ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr)
if err == nil && !ethAddr.IsMaskedID() {
return ethAddr, nil
}
// Lookup on the target actor and try to get an f410 address.
if actor, err := st.GetActor(addr); err != nil {
return ethtypes.EthAddress{}, err
} else if actor.Address != nil {
if ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address); err == nil && !ethAddr.IsMaskedID() {
return ethAddr, nil
}
}
// BLOCK B: We gave up on getting an actual Ethereum address and are falling back to a Masked ID address.
// Check if we already have an ID addr, and use it if possible.
if err == nil && ethAddr.IsMaskedID() {
return ethAddr, nil
}
// Otherwise, resolve the ID addr.
idAddr, err := st.LookupID(addr)
if err != nil {
return ethtypes.EthAddress{}, err
}
// Lookup on the target actor and try to get an f410 address.
if actor, err := st.GetActor(idAddr); errors.Is(err, types.ErrActorNotFound) {
// Not found -> use a masked ID address
} else if err != nil {
// Any other error -> fail.
return ethtypes.EthAddress{}, err
} else if actor.Address == nil {
// No delegated address -> use masked ID address.
} else if ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address); err == nil && !ethAddr.IsMaskedID() {
// Conversable into an eth address, use it.
return ethAddr, nil
}
// Otherwise, use the masked address.
return ethtypes.EthAddressFromFilecoinAddress(idAddr)
}