Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev/v1.12 #5936

Merged
merged 10 commits into from
Apr 25, 2023
19 changes: 4 additions & 15 deletions app/submodule/chain/chaininfo_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,25 +291,14 @@ func (cia *chainInfoAPI) ChainGetParentReceipts(ctx context.Context, bcid cid.Ci
return nil, nil
}

// TODO: need to get the number of messages better than this
pts, err := cia.chain.ChainReader.GetTipSet(ctx, types.NewTipSetKey(b.Parents...))
if err != nil {
return nil, err
}

cm, err := cia.chain.MessageStore.MessagesForTipset(pts)
receipts, err := cia.chain.MessageStore.LoadReceipts(ctx, b.ParentMessageReceipts)
if err != nil {
return nil, err
}

var out []*types.MessageReceipt
for i := 0; i < len(cm); i++ {
r, err := cia.chain.ChainReader.GetParentReceipt(b, i)
if err != nil {
return nil, err
}

out = append(out, r)
out := make([]*types.MessageReceipt, len(receipts))
for i := range receipts {
out[i] = &receipts[i]
}

return out, nil
Expand Down
9 changes: 9 additions & 0 deletions app/submodule/eth/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/go-state-types/abi"
v1 "github.com/filecoin-project/venus/venus-shared/api/chain/v1"
"github.com/filecoin-project/venus/venus-shared/types"
)
Expand Down Expand Up @@ -60,6 +61,10 @@ func (e *ethAPIDummy) EthGetTransactionByHash(ctx context.Context, txHash *types
return nil, ErrModuleDisabled
}

func (e *ethAPIDummy) EthGetTransactionByHashLimited(ctx context.Context, txHash *types.EthHash, limit abi.ChainEpoch) (*types.EthTx, error) {
return nil, ErrModuleDisabled
}

func (e *ethAPIDummy) EthGetTransactionCount(ctx context.Context, sender types.EthAddress, blkOpt string) (types.EthUint64, error) {
return 0, ErrModuleDisabled
}
Expand All @@ -68,6 +73,10 @@ func (e *ethAPIDummy) EthGetTransactionReceipt(ctx context.Context, txHash types
return nil, ErrModuleDisabled
}

func (e *ethAPIDummy) EthGetTransactionReceiptLimited(ctx context.Context, txHash types.EthHash, limit abi.ChainEpoch) (*types.EthTxReceipt, error) {
return nil, ErrModuleDisabled
}

func (e *ethAPIDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash types.EthHash, txIndex types.EthUint64) (types.EthTx, error) {
return types.EthTx{}, ErrModuleDisabled
}
Expand Down
149 changes: 87 additions & 62 deletions app/submodule/eth/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/filecoin-project/venus/pkg/fork"
"github.com/filecoin-project/venus/pkg/messagepool"
"github.com/filecoin-project/venus/pkg/statemanger"
"github.com/filecoin-project/venus/pkg/vm/gas"
"github.com/filecoin-project/venus/venus-shared/actors"
builtinactors "github.com/filecoin-project/venus/venus-shared/actors/builtin"
builtinevm "github.com/filecoin-project/venus/venus-shared/actors/builtin/evm"
Expand All @@ -43,6 +44,7 @@ import (
var log = logging.Logger("eth_api")

var ErrNullRound = errors.New("requested epoch was a null round")
var ErrUnsupported = errors.New("unsupported method")

func newEthAPI(em *EthSubModule) (*ethAPI, error) {
a := &ethAPI{
Expand Down Expand Up @@ -233,6 +235,10 @@ func (a *ethAPI) EthGetBlockByNumber(ctx context.Context, blkParam string, fullT
}

func (a *ethAPI) EthGetTransactionByHash(ctx context.Context, txHash *types.EthHash) (*types.EthTx, error) {
return a.EthGetTransactionByHashLimited(ctx, txHash, constants.LookbackNoLimit)
}

func (a *ethAPI) EthGetTransactionByHashLimited(ctx context.Context, txHash *types.EthHash, limit abi.ChainEpoch) (*types.EthTx, error) {
// Ethereum's behavior is to return null when the txHash is invalid, so we use nil to check if txHash is valid
if txHash == nil {
return nil, nil
Expand All @@ -249,7 +255,7 @@ func (a *ethAPI) EthGetTransactionByHash(ctx context.Context, txHash *types.EthH
}

// first, try to get the cid from mined transactions
msgLookup, err := a.chain.StateSearchMsg(ctx, types.EmptyTSK, c, constants.LookbackNoLimit, true)
msgLookup, err := a.chain.StateSearchMsg(ctx, types.EmptyTSK, c, limit, true)
if err == nil && msgLookup != nil {
tx, err := newEthTxFromMessageLookup(ctx, msgLookup, -1, a.em.chainModule.MessageStore, a.chain)
if err == nil {
Expand Down Expand Up @@ -363,6 +369,10 @@ func (a *ethAPI) EthGetTransactionCount(ctx context.Context, sender types.EthAdd
}

func (a *ethAPI) EthGetTransactionReceipt(ctx context.Context, txHash types.EthHash) (*types.EthTxReceipt, error) {
return a.EthGetTransactionReceiptLimited(ctx, txHash, constants.LookbackNoLimit)
}

func (a *ethAPI) EthGetTransactionReceiptLimited(ctx context.Context, txHash types.EthHash, limit abi.ChainEpoch) (*types.EthTxReceipt, error) {
c, err := a.ethTxHashManager.TransactionHashLookup.GetCidFromHash(txHash)
if err != nil {
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
Expand All @@ -373,7 +383,7 @@ func (a *ethAPI) EthGetTransactionReceipt(ctx context.Context, txHash types.EthH
c = txHash.ToCid()
}

msgLookup, err := a.chain.StateSearchMsg(ctx, types.EmptyTSK, c, constants.LookbackNoLimit, true)
msgLookup, err := a.chain.StateSearchMsg(ctx, types.EmptyTSK, c, limit, true)
if err != nil || msgLookup == nil {
return nil, nil
}
Expand All @@ -383,20 +393,15 @@ func (a *ethAPI) EthGetTransactionReceipt(ctx context.Context, txHash types.EthH
return nil, nil
}

replay, err := a.chain.StateReplay(ctx, types.EmptyTSK, c)
if err != nil {
return nil, nil
}

var events []types.Event
if rct := replay.MsgRct; rct != nil && rct.EventsRoot != nil {
if rct := msgLookup.Receipt; rct.EventsRoot != nil {
events, err = a.chain.ChainGetEvents(ctx, *rct.EventsRoot)
if err != nil {
return nil, nil
}
}

receipt, err := newEthTxReceipt(ctx, tx, msgLookup, replay, events, a.chain)
receipt, err := newEthTxReceipt(ctx, tx, msgLookup, events, a.chain)
if err != nil {
return nil, nil
}
Expand All @@ -405,11 +410,11 @@ func (a *ethAPI) EthGetTransactionReceipt(ctx context.Context, txHash types.EthH
}

func (a *ethAPI) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash types.EthHash, txIndex types.EthUint64) (types.EthTx, error) {
return types.EthTx{}, nil
return types.EthTx{}, ErrUnsupported
}

func (a *ethAPI) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum types.EthUint64, txIndex types.EthUint64) (types.EthTx, error) {
return types.EthTx{}, nil
return types.EthTx{}, ErrUnsupported
}

// EthGetCode returns string value of the compiled bytecode
Expand Down Expand Up @@ -627,7 +632,6 @@ func (a *ethAPI) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (types.
if params.BlkCount > 1024 {
return types.EthFeeHistory{}, fmt.Errorf("block count should be smaller than 1024")
}

rewardPercentiles := make([]float64, 0)
if params.RewardPercentiles != nil {
rewardPercentiles = append(rewardPercentiles, *params.RewardPercentiles...)
Expand All @@ -646,48 +650,39 @@ func (a *ethAPI) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (types.
return types.EthFeeHistory{}, fmt.Errorf("bad block parameter %s: %s", params.NewestBlkNum, err)
}

oldestBlkHeight := uint64(1)

// NOTE: baseFeePerGas should include the next block after the newest of the returned range,
// because the next base fee can be inferred from the messages in the newest block.
// However, this is NOT the case in Filecoin due to deferred execution, so the best
// we can do is duplicate the last value.
baseFeeArray := []types.EthBigInt{types.EthBigInt(ts.Blocks()[0].ParentBaseFee)}
gasUsedRatioArray := []float64{}
rewardsArray := make([][]types.EthBigInt, 0)
var (
basefee = ts.Blocks()[0].ParentBaseFee
oldestBlkHeight = uint64(1)

// NOTE: baseFeePerGas should include the next block after the newest of the returned range,
// because the next base fee can be inferred from the messages in the newest block.
// However, this is NOT the case in Filecoin due to deferred execution, so the best
// we can do is duplicate the last value.
baseFeeArray = []types.EthBigInt{types.EthBigInt(basefee)}
rewardsArray = make([][]types.EthBigInt, 0)
gasUsedRatioArray = []float64{}
blocksIncluded int
)

blocksIncluded := 0
for blocksIncluded < int(params.BlkCount) && ts.Height() > 0 {
compOutput, err := a.chain.StateCompute(ctx, ts.Height(), nil, ts.Key())
msgs, rcpts, err := a.messagesAndReceipts(ctx, ts)
if err != nil {
return types.EthFeeHistory{}, fmt.Errorf("cannot lookup the status of for tipset: %v: %w", ts, err)
return types.EthFeeHistory{}, fmt.Errorf("failed to retrieve messages and receipts for height %d: %w", ts.Height(), err)
}

txGasRewards := gasRewardSorter{}
for _, msg := range compOutput.Trace {
if msg.Msg.From == builtintypes.SystemActorAddr {
continue
}

smsgCid, err := getSignedMessage(ctx, a.em.chainModule.MessageStore, msg.MsgCid)
if err != nil {
return types.EthFeeHistory{}, fmt.Errorf("failed to get signed msg %s: %w", msg.MsgCid, err)
}
tx, err := newEthTxFromSignedMessage(ctx, smsgCid, a.chain)
if err != nil {
return types.EthFeeHistory{}, err
}

for i, msg := range msgs {
effectivePremium := msg.VMMessage().EffectiveGasPremium(basefee)
txGasRewards = append(txGasRewards, gasRewardTuple{
reward: tx.Reward(ts.Blocks()[0].ParentBaseFee),
gas: uint64(msg.MsgRct.GasUsed),
premium: effectivePremium,
gasUsed: rcpts[i].GasUsed,
})
}

rewards, totalGasUsed := calculateRewardsAndGasUsed(rewardPercentiles, txGasRewards)

// arrays should be reversed at the end
baseFeeArray = append(baseFeeArray, types.EthBigInt(ts.Blocks()[0].ParentBaseFee))
baseFeeArray = append(baseFeeArray, types.EthBigInt(basefee))
gasUsedRatioArray = append(gasUsedRatioArray, float64(totalGasUsed)/float64(constants.BlockGasLimit))
rewardsArray = append(rewardsArray, rewards)
oldestBlkHeight = uint64(ts.Height())
Expand Down Expand Up @@ -719,17 +714,11 @@ func (a *ethAPI) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (types.
if params.RewardPercentiles != nil {
ret.Reward = &rewardsArray
}

return ret, nil
}

func (a *ethAPI) NetVersion(ctx context.Context) (string, error) {
// Note that networkId is not encoded in hex
nv, err := a.chain.StateNetworkVersion(ctx, types.EmptyTSK)
if err != nil {
return "", err
}
return strconv.FormatUint(uint64(nv), 10), nil
return strconv.FormatInt(int64(types2.Eip155ChainID), 10), nil
}

func (a *ethAPI) NetListening(ctx context.Context) (bool, error) {
Expand Down Expand Up @@ -1335,7 +1324,7 @@ func newEthTxFromMessageLookup(ctx context.Context, msgLookup *types.MsgLookup,
return tx, nil
}

func newEthTxReceipt(ctx context.Context, tx types.EthTx, lookup *types.MsgLookup, replay *types.InvocResult, events []types.Event, ca v1.IChain) (types.EthTxReceipt, error) {
func newEthTxReceipt(ctx context.Context, tx types.EthTx, lookup *types.MsgLookup, events []types.Event, ca v1.IChain) (types.EthTxReceipt, error) {
var (
transactionIndex types.EthUint64
blockHash types.EthHash
Expand Down Expand Up @@ -1376,7 +1365,20 @@ func newEthTxReceipt(ctx context.Context, tx types.EthTx, lookup *types.MsgLooku
// TODO: handle CumulativeGasUsed
receipt.CumulativeGasUsed = types.EmptyEthInt

effectiveGasPrice := big.Div(replay.GasCost.TotalCost, big.NewInt(lookup.Receipt.GasUsed))
// TODO: avoid loading the tipset twice (once here, once when we convert the message to a txn)
ts, err := ca.ChainGetTipSet(ctx, lookup.TipSet)
if err != nil {
return types.EthTxReceipt{}, fmt.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", lookup.TipSet, err)
}

baseFee := ts.Blocks()[0].ParentBaseFee
gasOutputs := gas.ComputeGasOutputs(lookup.Receipt.GasUsed, int64(tx.Gas), baseFee, big.Int(tx.MaxFeePerGas), big.Int(tx.MaxPriorityFeePerGas), true)
totalSpent := big.Sum(gasOutputs.BaseFeeBurn, gasOutputs.MinerTip, gasOutputs.OverEstimationBurn)

effectiveGasPrice := big.Zero()
if lookup.Receipt.GasUsed > 0 {
effectiveGasPrice = big.Div(totalSpent, big.NewInt(lookup.Receipt.GasUsed))
}
receipt.EffectiveGasPrice = types.EthBigInt(effectiveGasPrice)

if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() {
Expand Down Expand Up @@ -1645,10 +1647,33 @@ func parseEthRevert(ret []byte) string {
return types.EthBytes(cbytes).String()
}

func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]types.EthBigInt, uint64) {
var totalGasUsed uint64
func (a *ethAPI) messagesAndReceipts(ctx context.Context, ts *types.TipSet) ([]types.ChainMsg, []types.MessageReceipt, error) {
msgs, err := a.em.chainModule.MessageStore.MessagesForTipset(ts)
if err != nil {
return nil, nil, fmt.Errorf("error loading messages for tipset: %v: %w", ts, err)
}

_, rcptRoot, err := a.em.chainModule.Stmgr.RunStateTransition(ctx, ts, nil, false)
if err != nil {
return nil, nil, fmt.Errorf("failed to compute state: %w", err)
}

rcpts, err := a.em.chainModule.MessageStore.LoadReceipts(ctx, rcptRoot)
if err != nil {
return nil, nil, fmt.Errorf("error loading receipts for tipset: %v: %w", ts, err)
}

if len(msgs) != len(rcpts) {
return nil, nil, fmt.Errorf("receipts and message array lengths didn't match for tipset: %v: %w", ts, err)
}

return msgs, rcpts, nil
}

func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]types.EthBigInt, int64) {
var gasUsedTotal int64
for _, tx := range txGasRewards {
totalGasUsed += tx.gas
gasUsedTotal += tx.gasUsed
}

rewards := make([]types.EthBigInt, len(rewardPercentiles))
Expand All @@ -1657,23 +1682,23 @@ func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRew
}

if len(txGasRewards) == 0 {
return rewards, totalGasUsed
return rewards, gasUsedTotal
}

sort.Stable(txGasRewards)

var idx int
var sum uint64
var sum int64
for i, percentile := range rewardPercentiles {
threshold := uint64(float64(totalGasUsed) * percentile / 100)
threshold := int64(float64(gasUsedTotal) * percentile / 100)
for sum < threshold && idx < len(txGasRewards)-1 {
sum += txGasRewards[idx].gas
sum += txGasRewards[idx].gasUsed
idx++
}
rewards[i] = txGasRewards[idx].reward
rewards[i] = types.EthBigInt(txGasRewards[idx].premium)
}

return rewards, totalGasUsed
return rewards, gasUsedTotal
}

func getSignedMessage(ctx context.Context, ms *chain.MessageStore, msgCid cid.Cid) (*types.SignedMessage, error) {
Expand All @@ -1696,8 +1721,8 @@ func getSignedMessage(ctx context.Context, ms *chain.MessageStore, msgCid cid.Ci
}

type gasRewardTuple struct {
gas uint64
reward types.EthBigInt
gasUsed int64
premium abi.TokenAmount
}

// sorted in ascending order
Expand All @@ -1708,7 +1733,7 @@ func (g gasRewardSorter) Swap(i, j int) {
g[i], g[j] = g[j], g[i]
}
func (g gasRewardSorter) Less(i, j int) bool {
return g[i].reward.Int.Cmp(g[j].reward.Int) == -1
return g[i].premium.Int.Cmp(g[j].premium.Int) == -1
}

var _ v1.IETH = &ethAPI{}
Expand Down
Loading