Middle · Blockchain infrastructure

eth_call succeeded; the transaction still failed

A contract call simulation succeeds, but a later submitted transaction reverts. Is this necessarily a bug in ABI encoding?

Try explaining this aloud before opening the answer. State your assumptions and trace a boundary case.

EXAMPLE · FRAGMENT UNLESS A COMPLETE PROGRAM IS SHOWN

go
package main

import (
	"fmt"
	"strings"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
)

func main() {
	schema := `[{"type":"function","name":"balanceOf","stateMutability":"view","inputs":[{"name":"owner","type":"address"}],"outputs":[{"name":"balance","type":"uint256"}]}]`
	parsed, err := abi.JSON(strings.NewReader(schema))
	if err != nil {
		panic(err)
	}
	raw := "0x0000000000000000000000000000000000000001"
	if !common.IsHexAddress(raw) {
		panic("invalid address")
	}
	data, err := parsed.Pack("balanceOf", common.HexToAddress(raw))
	if err != nil {
		panic(err)
	}
	fmt.Println(len(data)) // 4-byte selector + one 32-byte ABI word = 36
}
Reveal a strong answer
  1. An ABI describes how to encode a call and decode its result. It does not prove that the target address has the expected code or that a read result will remain true in a future transaction. An eth_call evaluates a call against a selected chain state without committing it. State-changing execution requires a separate signed transaction lifecycle and can fail even after a successful simulation.

  2. For reads, use ethclient.CallContract with an explicit block, or an appropriate hash-pinned call when reproducibility requires it. Decode with the same ABI and validate the returned shape. Generated bindings can make the Go surface clearer, but review the generated version and deployed contract compatibility; the newer bind/v2 API is not interchangeable with older binding examples. The example encodes an address into an ABI word without contacting a node or signing anything. HexToAddress is used only after validation, since conversion alone is not an input validator. The encoded bytes must still be paired with a verified chain, contract address and reviewed ABI before a native RPC call.

  3. A method name, ABI file or token symbol does not authenticate deployed code, particularly with upgradeable contracts. A successful simulation is not a promise about inclusion, fees or future state. Test malformed return data, wrong contract/network, a changed implementation, a reverted call and unavailable historical state. Keep signing policy outside a generic ABI helper.

Common trap

Successful simulation is not authorization or a guarantee of inclusion and successful state change.

Try it

Separate ABI packing, selected-state simulation, transaction construction, inclusion and receipt interpretation; name changes between each stage.

Worked solution

No. The simulation evaluated a selected state without committing it. The later transaction can encounter changed state, nonce, fees, permissions or contract implementation. ABI packing is only encoding, and a generated binding does not authenticate deployed code. Pin the intended chain and contract, decode and validate results, inspect the inclusion receipt and define how reverts and unknown send outcomes are reconciled.

Change the constraint

What is required to make a multi-read historical result reproducible by block hash?

How did you do?

Self-assessment, not a compiler pass or interview score. Explain the reasoning unaided before marking understood.

Not marked. Progress stays on this browser, separate from course completion.

Primary references

Checked 2026-10-28. Use documentation for your pinned runtime, driver and tool version.