fix: Eth JSON-RPC API: return empty logs array in receipt when no logs.
This commit is contained in:
parent
c474aeee5e
commit
b8901ff5fd
@ -836,3 +836,117 @@ func (a *EthModule) newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLo
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
<<<<<<< Updated upstream
|
||||
=======
|
||||
|
||||
func newEthTxReceipt(ctx context.Context, tx api.EthTx, lookup *api.MsgLookup, replay *api.InvocResult, events []types.Event, sa StateAPI) (api.EthTxReceipt, error) {
|
||||
receipt := api.EthTxReceipt{
|
||||
TransactionHash: tx.Hash,
|
||||
TransactionIndex: tx.TransactionIndex,
|
||||
BlockHash: tx.BlockHash,
|
||||
BlockNumber: tx.BlockNumber,
|
||||
From: tx.From,
|
||||
To: tx.To,
|
||||
Type: api.EthUint64(2),
|
||||
Logs: []api.EthLog{}, // empty log array is compulsory when no logs, or libraries like ethers.js break
|
||||
LogsBloom: []byte{0},
|
||||
}
|
||||
|
||||
if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() {
|
||||
// Create and Create2 return the same things.
|
||||
var ret eam.CreateReturn
|
||||
if err := ret.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil {
|
||||
return api.EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err)
|
||||
}
|
||||
addr := api.EthAddress(ret.EthAddress)
|
||||
receipt.ContractAddress = &addr
|
||||
}
|
||||
|
||||
if lookup.Receipt.ExitCode.IsSuccess() {
|
||||
receipt.Status = 1
|
||||
}
|
||||
if lookup.Receipt.ExitCode.IsError() {
|
||||
receipt.Status = 0
|
||||
}
|
||||
|
||||
if len(events) > 0 {
|
||||
// TODO return a dummy non-zero bloom to signal that there are logs
|
||||
// need to figure out how worth it is to populate with a real bloom
|
||||
// should be feasible here since we are iterating over the logs anyway
|
||||
receipt.LogsBloom = make([]byte, 256)
|
||||
receipt.LogsBloom[255] = 0x01
|
||||
|
||||
receipt.Logs = make([]api.EthLog, 0, len(events))
|
||||
for i, evt := range events {
|
||||
l := api.EthLog{
|
||||
Removed: false,
|
||||
LogIndex: api.EthUint64(i),
|
||||
TransactionIndex: tx.TransactionIndex,
|
||||
TransactionHash: tx.Hash,
|
||||
BlockHash: tx.BlockHash,
|
||||
BlockNumber: tx.BlockNumber,
|
||||
}
|
||||
|
||||
for _, entry := range evt.Entries {
|
||||
value := api.EthBytes(leftpad32(decodeLogBytes(entry.Value)))
|
||||
if entry.Key == api.EthTopic1 || entry.Key == api.EthTopic2 || entry.Key == api.EthTopic3 || entry.Key == api.EthTopic4 {
|
||||
l.Topics = append(l.Topics, value)
|
||||
} else {
|
||||
l.Data = value
|
||||
}
|
||||
}
|
||||
|
||||
addr, err := address.NewIDAddress(uint64(evt.Emitter))
|
||||
if err != nil {
|
||||
return api.EthTxReceipt{}, xerrors.Errorf("failed to create ID address: %w", err)
|
||||
}
|
||||
|
||||
l.Address, err = lookupEthAddress(ctx, addr, sa)
|
||||
if err != nil {
|
||||
return api.EthTxReceipt{}, xerrors.Errorf("failed to resolve Ethereum address: %w", err)
|
||||
}
|
||||
|
||||
receipt.Logs = append(receipt.Logs, l)
|
||||
}
|
||||
}
|
||||
|
||||
receipt.GasUsed = api.EthUint64(lookup.Receipt.GasUsed)
|
||||
|
||||
// TODO: handle CumulativeGasUsed
|
||||
receipt.CumulativeGasUsed = api.EmptyEthInt
|
||||
|
||||
effectiveGasPrice := big.Div(replay.GasCost.TotalCost, big.NewInt(lookup.Receipt.GasUsed))
|
||||
receipt.EffectiveGasPrice = api.EthBigInt(effectiveGasPrice)
|
||||
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
// decodeLogBytes decodes a CBOR-serialized array into its original form.
|
||||
//
|
||||
// This function swallows errors and returns the original array if it failed
|
||||
// to decode.
|
||||
func decodeLogBytes(orig []byte) []byte {
|
||||
if orig == nil {
|
||||
return orig
|
||||
}
|
||||
decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig)))
|
||||
if err != nil {
|
||||
return orig
|
||||
}
|
||||
return decoded
|
||||
}
|
||||
|
||||
// TODO we could also emit full EVM words from the EVM runtime, but not doing so
|
||||
// makes the contract slightly cheaper (and saves storage bytes), at the expense
|
||||
// of having to left pad in the API, which is a pretty acceptable tradeoff at
|
||||
// face value. There may be other protocol implications to consider.
|
||||
func leftpad32(orig []byte) []byte {
|
||||
needed := 32 - len(orig)
|
||||
if needed <= 0 {
|
||||
return orig
|
||||
}
|
||||
ret := make([]byte, 32)
|
||||
copy(ret[needed:], orig)
|
||||
return ret
|
||||
}
|
||||
>>>>>>> Stashed changes
|
||||
|
Loading…
Reference in New Issue
Block a user