Skip to content

Commit f8f2d3c

Browse files
authored
Merge pull request #12 from TacBuild/tac-simulate-rpc
feat: Tac simulate rpc
2 parents 8e01bec + a3949a4 commit f8f2d3c

26 files changed

Lines changed: 4372 additions & 587 deletions

api/cosmos/evm/vm/v1/query.pulsar.go

Lines changed: 1965 additions & 310 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/cosmos/evm/vm/v1/query_grpc.pb.go

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/cosmos/evm/vm/v1/query.proto

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ service Query {
5959
option (google.api.http).get = "/cosmos/evm/vm/v1/eth_call";
6060
}
6161

62+
// TacSimulate implements the custom `tac_simulate` rpc api which supports state override
63+
rpc TacSimulate(TacSimulateRequest) returns (TacSimulateResponse) {
64+
option (google.api.http).get = "/cosmos/evm/vm/v1/tac_simulate";
65+
}
66+
6267
// EstimateGas implements the `eth_estimateGas` rpc api
6368
rpc EstimateGas(EthCallRequest) returns (EstimateGasResponse) {
6469
option (google.api.http).get = "/cosmos/evm/vm/v1/estimate_gas";
@@ -260,6 +265,40 @@ message EthCallRequest {
260265
int64 chain_id = 4;
261266
}
262267

268+
// TacSimulateRequest defines TacSimulate request
269+
message TacSimulateRequest {
270+
// args uses the same json format as the json rpc api.
271+
bytes args = 1;
272+
// state_override defines the state override for the call, it uses the same json format as the json rpc api.
273+
bytes state_override = 2;
274+
// gas_cap defines the default gas cap to be used
275+
uint64 gas_cap = 3;
276+
// proposer_address of the requested block in hex format
277+
bytes proposer_address = 4
278+
[ (gogoproto.casttype) =
279+
"github.com/cosmos/cosmos-sdk/types.ConsAddress" ];
280+
// chain_id is the eip155 chain id parsed from the requested block header
281+
int64 chain_id = 5;
282+
}
283+
284+
// TacSimulateResponse defines TacSimulate response
285+
message TacSimulateResponse {
286+
// hash of the ethereum transaction in hex format
287+
string hash = 1;
288+
// logs contains the proto-compatible ethereum logs
289+
repeated Log logs = 2;
290+
// ret is the returned data from evm function (result or data supplied with
291+
// revert opcode)
292+
bytes ret = 3;
293+
// vm_error is the error returned by vm execution
294+
string vm_error = 4;
295+
// gas_used specifies how much gas was consumed by the EVM execution
296+
uint64 gas_used = 5;
297+
// gas_estimated is the estimated minimum gas limit needed to execute
298+
// the transaction successfully (result of binary search, like eth_estimateGas)
299+
uint64 gas_estimated = 6;
300+
}
301+
263302
// EstimateGasResponse defines EstimateGas response
264303
message EstimateGasResponse {
265304
// gas returns the estimated gas

rpc/apis.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/cosmos/evm/rpc/namespaces/ethereum/miner"
1515
"github.com/cosmos/evm/rpc/namespaces/ethereum/net"
1616
"github.com/cosmos/evm/rpc/namespaces/ethereum/personal"
17+
"github.com/cosmos/evm/rpc/namespaces/ethereum/tac"
1718
"github.com/cosmos/evm/rpc/namespaces/ethereum/txpool"
1819
"github.com/cosmos/evm/rpc/namespaces/ethereum/web3"
1920
"github.com/cosmos/evm/types"
@@ -37,6 +38,7 @@ const (
3738
TxPoolNamespace = "txpool"
3839
DebugNamespace = "debug"
3940
MinerNamespace = "miner"
41+
TacNamespace = "tac"
4042

4143
apiVersion = "1.0"
4244
)
@@ -155,6 +157,22 @@ func init() {
155157
},
156158
}
157159
},
160+
TacNamespace: func(ctx *server.Context,
161+
clientCtx client.Context,
162+
_ *rpcclient.WSClient,
163+
allowUnprotectedTxs bool,
164+
indexer types.EVMTxIndexer,
165+
) []rpc.API {
166+
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer)
167+
return []rpc.API{
168+
{
169+
Namespace: TacNamespace,
170+
Version: apiVersion,
171+
Service: tac.NewTacAPI(ctx.Logger, evmBackend),
172+
Public: true,
173+
},
174+
}
175+
},
158176
}
159177
}
160178

rpc/backend/backend.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ type EVMBackend interface {
110110
SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error)
111111
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rpctypes.BlockNumber) (hexutil.Uint64, error)
112112
DoCall(args evmtypes.TransactionArgs, blockNr rpctypes.BlockNumber) (*evmtypes.MsgEthereumTxResponse, error)
113+
DoTacSimulate(args evmtypes.TransactionArgs, blockNr rpctypes.BlockNumber, stateOverride evmtypes.StateOverride) (*evmtypes.TacSimulateResponse, error)
113114
GasPrice() (*hexutil.Big, error)
114115

115116
// Filter API

rpc/backend/call_tx.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,66 @@ func (b *Backend) DoCall(
372372
return res, nil
373373
}
374374

375+
func (b *Backend) DoTacSimulate(
376+
args evmtypes.TransactionArgs,
377+
blockNr rpctypes.BlockNumber,
378+
stateOverride evmtypes.StateOverride,
379+
) (*evmtypes.TacSimulateResponse, error) {
380+
bz, err := json.Marshal(&args)
381+
if err != nil {
382+
return nil, err
383+
}
384+
385+
header, err := b.TendermintBlockByNumber(blockNr)
386+
if err != nil {
387+
// the error message imitates geth behavior
388+
return nil, errors.New("header not found")
389+
}
390+
391+
overrideBz, err := json.Marshal(stateOverride)
392+
if err != nil {
393+
return nil, err
394+
}
395+
396+
req := evmtypes.TacSimulateRequest{
397+
Args: bz,
398+
GasCap: b.RPCGasCap(),
399+
ProposerAddress: sdk.ConsAddress(header.Block.ProposerAddress),
400+
ChainId: b.chainID.Int64(),
401+
StateOverride: overrideBz,
402+
}
403+
404+
// From ContextWithHeight: if the provided height is 0,
405+
// it will return an empty context and the gRPC query will use
406+
// the latest block height for querying.
407+
ctx := rpctypes.ContextWithHeight(blockNr.Int64())
408+
timeout := b.RPCEVMTimeout()
409+
410+
// Setup context so it may be canceled the call has completed
411+
// or, in case of unmetered gas, setup a context with a timeout.
412+
var cancel context.CancelFunc
413+
if timeout > 0 {
414+
ctx, cancel = context.WithTimeout(ctx, timeout)
415+
} else {
416+
ctx, cancel = context.WithCancel(ctx)
417+
}
418+
419+
// Make sure the context is canceled when the call has completed
420+
// this makes sure resources are cleaned up.
421+
defer cancel()
422+
423+
res, err := b.queryClient.TacSimulate(ctx, &req)
424+
if err != nil {
425+
return nil, err
426+
}
427+
428+
if err = handleRevertError(res.VmError, res.Ret); err != nil {
429+
return nil, err
430+
}
431+
432+
return res, nil
433+
}
434+
375435
// GasPrice returns the current gas price based on Cosmos EVM' gas price oracle.
376436
func (b *Backend) GasPrice() (*hexutil.Big, error) {
377437
var (

0 commit comments

Comments
 (0)