/
estimate_fee.go
151 lines (131 loc) · 4.4 KB
/
estimate_fee.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package rpc
import (
"encoding/json"
"errors"
"fmt"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/juno/jsonrpc"
"github.com/NethermindEth/juno/utils"
)
type FeeUnit byte
const (
WEI FeeUnit = iota
FRI
)
func (u FeeUnit) MarshalText() ([]byte, error) {
switch u {
case WEI:
return []byte("WEI"), nil
case FRI:
return []byte("FRI"), nil
default:
return nil, fmt.Errorf("unknown FeeUnit %v", u)
}
}
type FeeEstimate struct {
GasConsumed *felt.Felt `json:"gas_consumed"`
GasPrice *felt.Felt `json:"gas_price"`
DataGasConsumed *felt.Felt `json:"data_gas_consumed"`
DataGasPrice *felt.Felt `json:"data_gas_price"`
OverallFee *felt.Felt `json:"overall_fee"`
Unit *FeeUnit `json:"unit,omitempty"`
// pre 13.1 response
v0_6Response bool
}
func (f FeeEstimate) MarshalJSON() ([]byte, error) {
if f.v0_6Response {
return json.Marshal(struct {
GasConsumed *felt.Felt `json:"gas_consumed"`
GasPrice *felt.Felt `json:"gas_price"`
OverallFee *felt.Felt `json:"overall_fee"`
Unit *FeeUnit `json:"unit,omitempty"`
}{
GasConsumed: f.GasConsumed,
GasPrice: f.GasPrice,
OverallFee: f.OverallFee,
Unit: f.Unit,
})
} else {
type alias FeeEstimate // avoid infinite recursion
return json.Marshal(alias(f))
}
}
/****************************************************
Estimate Fee Handlers
*****************************************************/
func (h *Handler) EstimateFee(broadcastedTxns []BroadcastedTransaction,
simulationFlags []SimulationFlag, id BlockID,
) ([]FeeEstimate, *jsonrpc.Error) {
result, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), false, true)
if err != nil {
return nil, err
}
return utils.Map(result, func(tx SimulatedTransaction) FeeEstimate {
return tx.FeeEstimation
}), nil
}
func (h *Handler) EstimateFeeV0_6(broadcastedTxns []BroadcastedTransaction,
simulationFlags []SimulationFlag, id BlockID,
) ([]FeeEstimate, *jsonrpc.Error) {
result, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true, true)
if err != nil {
return nil, err
}
return utils.Map(result, func(tx SimulatedTransaction) FeeEstimate {
return tx.FeeEstimation
}), nil
}
func (h *Handler) EstimateMessageFee(msg MsgFromL1, id BlockID) (*FeeEstimate, *jsonrpc.Error) { //nolint:gocritic
return h.estimateMessageFee(msg, id, h.EstimateFee)
}
func (h *Handler) EstimateMessageFeeV0_6(msg MsgFromL1, id BlockID) (*FeeEstimate, *jsonrpc.Error) { //nolint:gocritic
feeEstimate, rpcErr := h.estimateMessageFee(msg, id, h.EstimateFeeV0_6)
if rpcErr != nil {
return nil, rpcErr
}
feeEstimate.v0_6Response = true
feeEstimate.DataGasPrice = nil
feeEstimate.DataGasConsumed = nil
return feeEstimate, nil
}
type estimateFeeHandler func(broadcastedTxns []BroadcastedTransaction,
simulationFlags []SimulationFlag, id BlockID,
) ([]FeeEstimate, *jsonrpc.Error)
func (h *Handler) estimateMessageFee(msg MsgFromL1, id BlockID, f estimateFeeHandler) (*FeeEstimate, *jsonrpc.Error) { //nolint:gocritic
calldata := make([]*felt.Felt, 0, len(msg.Payload)+1)
// The order of the calldata parameters matters. msg.From must be prepended.
calldata = append(calldata, new(felt.Felt).SetBytes(msg.From.Bytes()))
for payloadIdx := range msg.Payload {
calldata = append(calldata, &msg.Payload[payloadIdx])
}
tx := BroadcastedTransaction{
Transaction: Transaction{
Type: TxnL1Handler,
ContractAddress: &msg.To,
EntryPointSelector: &msg.Selector,
CallData: &calldata,
Version: &felt.Zero, // Needed for transaction hash calculation.
Nonce: &felt.Zero, // Needed for transaction hash calculation.
},
// Needed to marshal to blockifier type.
// Must be greater than zero to successfully execute transaction.
PaidFeeOnL1: new(felt.Felt).SetUint64(1),
}
estimates, rpcErr := f([]BroadcastedTransaction{tx}, nil, id)
if rpcErr != nil {
if rpcErr.Code == ErrTransactionExecutionError.Code {
data := rpcErr.Data.(TransactionExecutionErrorData)
return nil, makeContractError(errors.New(data.ExecutionError))
}
return nil, rpcErr
}
return &estimates[0], nil
}
type ContractErrorData struct {
RevertError string `json:"revert_error"`
}
func makeContractError(err error) *jsonrpc.Error {
return ErrContractError.CloneWithData(ContractErrorData{
RevertError: err.Error(),
})
}