Skip to content

Commit 7f9ab01

Browse files
committed
apply
1 parent 97860f9 commit 7f9ab01

File tree

4 files changed

+158
-13
lines changed

4 files changed

+158
-13
lines changed

rpc/backend/call_tx.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -372,19 +372,6 @@ func (b *Backend) DoCall(
372372
return nil, errors.New("header not found")
373373
}
374374

375-
var bzOverrides []byte
376-
if overrides != nil {
377-
bzOverrides = *overrides
378-
}
379-
380-
req := evmtypes.EthCallRequest{
381-
Args: bz,
382-
GasCap: b.RPCGasCap(),
383-
ProposerAddress: sdk.ConsAddress(header.Header.ProposerAddress),
384-
ChainId: b.EvmChainID.Int64(),
385-
Overrides: bzOverrides,
386-
}
387-
388375
// From ContextWithHeight: if the provided height is 0,
389376
// it will return an empty context and the gRPC query will use
390377
// the latest block height for querying.
@@ -404,6 +391,36 @@ func (b *Backend) DoCall(
404391
// this makes sure resources are cleaned up.
405392
defer cancel()
406393

394+
var isDynamic bool
395+
if args.To != nil {
396+
precompileReq := &evmtypes.QueryPrecompileRequest{Address: args.To.Hex()}
397+
if res, err := b.QueryClient.Precompile(ctx, precompileReq); err == nil {
398+
isDynamic = res.IsPrecompile && !res.IsStatic
399+
}
400+
}
401+
402+
evmOverrides, cosmosOverrides, err := rpctypes.ParseOverrides(overrides, isDynamic)
403+
if err != nil {
404+
return nil, fmt.Errorf("failed to parse overrides: %w", err)
405+
}
406+
407+
var bzOverrides []byte
408+
if evmOverrides != nil {
409+
bzOverrides, err = json.Marshal(evmOverrides)
410+
if err != nil {
411+
return nil, fmt.Errorf("failed to marshal EVM overrides: %w", err)
412+
}
413+
}
414+
415+
req := evmtypes.EthCallRequest{
416+
Args: bz,
417+
GasCap: b.RPCGasCap(),
418+
ProposerAddress: sdk.ConsAddress(header.Header.ProposerAddress),
419+
ChainId: b.EvmChainID.Int64(),
420+
Overrides: bzOverrides,
421+
StateOverrides: cosmosOverrides,
422+
}
423+
407424
res, err := b.QueryClient.EthCall(ctx, &req)
408425
if err != nil {
409426
return nil, err

rpc/types/types.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package types
22

33
import (
4+
"encoding/base64"
45
"encoding/json"
56
"fmt"
67
"math/big"
@@ -189,3 +190,65 @@ type TraceConfig struct {
189190
evmtypes.TraceConfig
190191
TracerConfig json.RawMessage `json:"tracerConfig"`
191192
}
193+
194+
// ParseOverrides attempts to parse overrides as StateOverride
195+
// If isDynamicPrecompile is true, it will handle aligned cosmos override format for the target dynamic precompile
196+
func ParseOverrides(overrides *json.RawMessage, isDynamicPrecompile bool) (*StateOverride, []evmtypes.StoreStateDiff, error) {
197+
if overrides == nil {
198+
return nil, nil, nil
199+
}
200+
201+
if isDynamicPrecompile {
202+
var rawOverrides map[string]interface{}
203+
if err := json.Unmarshal(*overrides, &rawOverrides); err == nil {
204+
for _, encodedData := range rawOverrides {
205+
if overrideAccount, ok := encodedData.(map[string]interface{}); ok {
206+
if cosmosOverrides := extractFromOverrideAccount(overrideAccount); cosmosOverrides != nil {
207+
return nil, cosmosOverrides, nil
208+
}
209+
}
210+
if encodedStr, ok := encodedData.(string); ok {
211+
if cosmosOverrides := decodeCosmosOverrides(encodedStr); cosmosOverrides != nil {
212+
return nil, cosmosOverrides, nil
213+
}
214+
}
215+
}
216+
}
217+
}
218+
219+
var res StateOverride
220+
if err := json.Unmarshal(*overrides, &res); err != nil {
221+
return nil, nil, fmt.Errorf("failed to parse overrides: %w", err)
222+
}
223+
if len(res) == 0 {
224+
return nil, nil, nil
225+
}
226+
return &res, nil, nil
227+
}
228+
229+
// extractFromOverrideAccount extracts cosmos overrides from state/stateDiff fields
230+
func extractFromOverrideAccount(overrideAccount map[string]interface{}) []evmtypes.StoreStateDiff {
231+
for stateType, stateValue := range overrideAccount {
232+
if (stateType == "state" || stateType == "stateDiff") && stateValue != nil {
233+
if encodedStr, ok := stateValue.(string); ok {
234+
if cosmosOverrides := decodeCosmosOverrides(encodedStr); cosmosOverrides != nil {
235+
return cosmosOverrides
236+
}
237+
}
238+
}
239+
}
240+
return nil
241+
}
242+
243+
// decodeCosmosOverrides decodes base64 string and unmarshals cosmos overrides
244+
func decodeCosmosOverrides(encodedStr string) []evmtypes.StoreStateDiff {
245+
decodedBytes, err := base64.StdEncoding.DecodeString(encodedStr)
246+
if err != nil {
247+
return nil
248+
}
249+
var cosmosOverrides []evmtypes.StoreStateDiff
250+
if err := json.Unmarshal(decodedBytes, &cosmosOverrides); err != nil {
251+
return nil
252+
}
253+
return cosmosOverrides
254+
}

x/vm/keeper/grpc_query.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms
239239
}
240240

241241
ctx := sdk.UnwrapSDKContext(c)
242+
for _, stateOverride := range req.StateOverrides {
243+
if err := stateOverride.Apply(ctx, k.storeKeys); err != nil {
244+
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid state override: %s", err.Error()))
245+
}
246+
}
242247

243248
var args types.TransactionArgs
244249
err := json.Unmarshal(req.Args, &args)
@@ -869,6 +874,37 @@ func (k Keeper) GlobalMinGasPrice(c context.Context, _ *types.QueryGlobalMinGasP
869874
return &types.QueryGlobalMinGasPriceResponse{MinGasPrice: minGasPrice}, nil
870875
}
871876

877+
// Precompile implements the Query/Precompile gRPC method
878+
func (k Keeper) Precompile(c context.Context, req *types.QueryPrecompileRequest) (*types.QueryPrecompileResponse, error) {
879+
if req == nil {
880+
return nil, status.Error(codes.InvalidArgument, "empty request")
881+
}
882+
883+
if !common.IsHexAddress(req.Address) {
884+
return nil, status.Error(codes.InvalidArgument, "invalid address")
885+
}
886+
887+
ctx := sdk.UnwrapSDKContext(c)
888+
address := common.HexToAddress(req.Address)
889+
890+
_, found, err := k.GetPrecompileInstance(ctx, address)
891+
if err != nil {
892+
return nil, status.Error(codes.Internal, err.Error())
893+
}
894+
895+
isStatic := false
896+
if found {
897+
params := k.GetParams(ctx)
898+
_, staticFound, _ := k.GetStaticPrecompileInstance(&params, address)
899+
isStatic = staticFound
900+
}
901+
902+
return &types.QueryPrecompileResponse{
903+
IsPrecompile: found,
904+
IsStatic: isStatic,
905+
}, nil
906+
}
907+
872908
// Config implements the Query/Config gRPC method
873909
func (k Keeper) Config(_ context.Context, _ *types.QueryConfigRequest) (*types.QueryConfigResponse, error) {
874910
config := types.GetChainConfig()

x/vm/types/query.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
package types
22

3+
import (
4+
"fmt"
5+
6+
storetypes "cosmossdk.io/store/types"
7+
8+
sdk "github.com/cosmos/cosmos-sdk/types"
9+
)
10+
311
// Failed returns if the contract execution failed in vm errors
412
func (egr EstimateGasResponse) Failed() bool {
513
return len(egr.VmError) > 0
614
}
15+
16+
// Apply applies the state overrides to the given context's KVStore.
17+
// This allows overriding specific keys in the Cosmos SDK state during EVM calls.
18+
func (s *StoreStateDiff) Apply(ctx sdk.Context, storeKeys map[string]*storetypes.KVStoreKey) error {
19+
if s == nil {
20+
return nil
21+
}
22+
storeKey, exists := storeKeys[s.Name]
23+
if !exists {
24+
return fmt.Errorf("store key %s not found", s.Name)
25+
}
26+
kvStore := ctx.KVStore(storeKey)
27+
for _, entry := range s.Entries {
28+
if entry.Delete {
29+
kvStore.Delete(entry.Key)
30+
} else {
31+
kvStore.Set(entry.Key, entry.Value)
32+
}
33+
}
34+
return nil
35+
}

0 commit comments

Comments
 (0)