Skip to content

Commit

Permalink
Merge pull request #6036 from onflow/ramtin/6035-expose-error-msg-as-…
Browse files Browse the repository at this point in the history
…part-of-event

Exposing error msg as part of EVM transaction event
  • Loading branch information
ramtinms authored Jun 5, 2024
2 parents 9ed318b + 84f5a5a commit 0658967
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 5 deletions.
2 changes: 1 addition & 1 deletion engine/execution/state/bootstrap/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestBootstrapLedger(t *testing.T) {
}

func TestBootstrapLedger_ZeroTokenSupply(t *testing.T) {
expectedStateCommitmentBytes, _ := hex.DecodeString("29e6236ec00e2eebf21623fbd667c9c3fc07f392ec119bac37b294cb502e92d1,")
expectedStateCommitmentBytes, _ := hex.DecodeString("909ef788fb5c7eaf0f58e81c4c7853557785867fa514ac52ef43cdeb23eb2498,")
expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes)
require.NoError(t, err)

Expand Down
9 changes: 9 additions & 0 deletions fvm/evm/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ func TestEVMRun(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.StatusSuccessful, res.Status)
require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
require.Empty(t, res.ErrorMessage)
require.Nil(t, res.DeployedContractAddress)
require.Equal(t, num, new(big.Int).SetBytes(res.ReturnedValue).Int64())
})
Expand Down Expand Up @@ -315,6 +316,7 @@ func TestEVMRun(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.StatusSuccessful, res.Status)
require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
require.Empty(t, res.ErrorMessage)
require.Equal(t, int64(0), new(big.Int).SetBytes(res.ReturnedValue).Int64())
})
})
Expand Down Expand Up @@ -581,6 +583,7 @@ func TestEVMBatchRun(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.StatusSuccessful, res.Status)
require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
require.Empty(t, res.ErrorMessage)
require.Equal(t, storedValues[len(storedValues)-1], new(big.Int).SetBytes(res.ReturnedValue).Int64())
})
})
Expand Down Expand Up @@ -720,6 +723,7 @@ func TestEVMBatchRun(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.StatusSuccessful, res.Status)
require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
require.Empty(t, res.ErrorMessage)
require.Equal(t, num, new(big.Int).SetBytes(res.ReturnedValue).Int64())
})
})
Expand Down Expand Up @@ -755,9 +759,11 @@ func TestEVMBatchRun(t *testing.T) {
if i %% 2 != 0 {
assert(res.status == EVM.Status.successful, message: "unexpected success status")
assert(res.errorCode == 0, message: "unexpected error code")
assert(res.errorMessage == "", message: "unexpected error msg")
} else {
assert(res.status == EVM.Status.failed, message: "unexpected failed status")
assert(res.errorCode == 301, message: "unexpected error code")
assert(res.errorMessage == "out of gas", message: "unexpected error msg")
}
}
}
Expand Down Expand Up @@ -862,6 +868,7 @@ func TestEVMBatchRun(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
require.Equal(t, types.StatusSuccessful, res.Status)
require.Empty(t, res.ErrorMessage)
require.Equal(t, num, new(big.Int).SetBytes(res.ReturnedValue).Int64())
})
})
Expand Down Expand Up @@ -925,6 +932,7 @@ func TestEVMBlockData(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.StatusSuccessful, res.Status)
require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
require.Empty(t, res.ErrorMessage)
require.Equal(t, ctx.BlockHeader.Timestamp.Unix(), new(big.Int).SetBytes(res.ReturnedValue).Int64())

})
Expand Down Expand Up @@ -1353,6 +1361,7 @@ func TestCadenceOwnedAccountFunctionalities(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.StatusSuccessful, res.Status)
require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
require.Empty(t, res.ErrorMessage)
require.NotNil(t, res.DeployedContractAddress)
// we strip away first few bytes because they contain deploy code
require.Equal(t, testContract.ByteCode[17:], []byte(res.ReturnedValue))
Expand Down
6 changes: 6 additions & 0 deletions fvm/evm/stdlib/contract.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ contract EVM {
access(all)
let errorCode: UInt64

/// error message
access(all)
let errorMessage: String

/// returns the amount of gas metered during
/// evm execution
access(all)
Expand All @@ -279,12 +283,14 @@ contract EVM {
init(
status: Status,
errorCode: UInt64,
errorMessage: String,
gasUsed: UInt64,
data: [UInt8],
contractAddress: [UInt8; 20]?
) {
self.status = status
self.errorCode = errorCode
self.errorMessage = errorMessage
self.gasUsed = gasUsed
self.data = data

Expand Down
18 changes: 17 additions & 1 deletion fvm/evm/stdlib/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const (
evmResultTypeQualifiedIdentifier = "EVM.Result"
evmResultTypeStatusFieldName = "status"
evmResultTypeErrorCodeFieldName = "errorCode"
evmResultTypeErrorMessageFieldName = "errorMessage"
evmResultTypeGasUsedFieldName = "gasUsed"
evmResultTypeDataFieldName = "data"
evmResultTypeDeployedContractFieldName = "deployedContract"
Expand Down Expand Up @@ -1272,6 +1273,15 @@ func NewResultValue(
return uint64(result.ErrorCode)
}),
},
{
Name: "errorMessage",
Value: interpreter.NewStringValue(inter,
common.NewStringMemoryUsage(len(result.ErrorMessage)),
func() string {
return result.ErrorMessage
},
),
},
{
Name: "gasUsed",
Value: interpreter.NewUInt64Value(gauge, func() uint64 {
Expand Down Expand Up @@ -2287,7 +2297,7 @@ func ResultSummaryFromEVMResultValue(val cadence.Value) (*types.ResultSummary, e

fields := cadence.FieldsMappedByName(str)

const expectedFieldCount = 5
const expectedFieldCount = 6
if len(fields) != expectedFieldCount {
return nil, fmt.Errorf(
"invalid input: field count mismatch: expected %d, got %d",
Expand All @@ -2311,6 +2321,11 @@ func ResultSummaryFromEVMResultValue(val cadence.Value) (*types.ResultSummary, e
return nil, fmt.Errorf("invalid input: unexpected type for error code field")
}

errorMsg, ok := fields[evmResultTypeErrorMessageFieldName].(cadence.String)
if !ok {
return nil, fmt.Errorf("invalid input: unexpected type for error msg field")
}

gasUsed, ok := fields[evmResultTypeGasUsedFieldName].(cadence.UInt64)
if !ok {
return nil, fmt.Errorf("invalid input: unexpected type for gas field")
Expand Down Expand Up @@ -2355,6 +2370,7 @@ func ResultSummaryFromEVMResultValue(val cadence.Value) (*types.ResultSummary, e
return &types.ResultSummary{
Status: types.Status(status),
ErrorCode: types.ErrorCode(errorCode),
ErrorMessage: string(errorMsg),
GasConsumed: uint64(gasUsed),
ReturnedValue: convertedData,
DeployedContractAddress: convertedDeployedAddress,
Expand Down
13 changes: 13 additions & 0 deletions fvm/evm/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ func (p *transactionEvent) ToCadence(location common.Location) (cadence.Event, e
deployedAddress = cadence.String(p.Result.DeployedContractAddress.String())
}

errorMsg := ""
if p.Result.VMError != nil {
errorMsg = p.Result.VMError.Error()
}
// both error would never happen at the same time
// but in case the priority is by validation error
if p.Result.ValidationError != nil {
errorMsg = p.Result.ValidationError.Error()
}

eventType := cadence.NewEventType(
location,
string(EventTypeTransactionExecuted),
Expand All @@ -88,6 +98,7 @@ func (p *transactionEvent) ToCadence(location common.Location) (cadence.Event, e
cadence.NewField("blockHeight", cadence.UInt64Type),
// todo we can remove hash and just reference block by height (evm-gateway dependency)
cadence.NewField("blockHash", cadence.StringType),
cadence.NewField("errorMessage", cadence.StringType),
},
nil,
)
Expand All @@ -103,6 +114,7 @@ func (p *transactionEvent) ToCadence(location common.Location) (cadence.Event, e
cadence.String(hex.EncodeToString(encodedLogs)),
cadence.NewUInt64(p.BlockHeight),
cadence.String(p.BlockHash.String()),
cadence.String(errorMsg),
}).WithType(eventType), nil
}

Expand Down Expand Up @@ -189,6 +201,7 @@ type TransactionEventPayload struct {
Logs string `cadence:"logs"`
BlockHeight uint64 `cadence:"blockHeight"`
BlockHash string `cadence:"blockHash"`
ErrorMessage string `cadence:"errorMessage"`
}

// DecodeTransactionEventPayload decodes Cadence event into transaction event payload.
Expand Down
2 changes: 2 additions & 0 deletions fvm/evm/types/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func TestEVMTransactionExecutedEventCCFEncodingDecoding(t *testing.T) {
assert.Equal(t, types.ErrorCode(tep.ErrorCode), types.ExecutionErrCodeOutOfGas)
assert.Equal(t, tep.TransactionType, txResult.TxType)
assert.Equal(t, tep.GasConsumed, txResult.GasConsumed)
assert.Equal(t, tep.ErrorMessage, txResult.VMError.Error())
assert.Equal(
t,
tep.ContractAddress,
Expand Down Expand Up @@ -173,6 +174,7 @@ func TestEVMTransactionExecutedEventCCFEncodingDecoding(t *testing.T) {
assert.Equal(t, types.ErrCodeNoError, types.ErrorCode(tep.ErrorCode))
assert.Equal(t, tep.TransactionType, txResult.TxType)
assert.Equal(t, tep.GasConsumed, txResult.GasConsumed)
assert.Empty(t, tep.ErrorMessage)
assert.NotNil(t, txResult.DeployedContractAddress)
assert.Equal(
t,
Expand Down
3 changes: 3 additions & 0 deletions fvm/evm/types/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var (
type ResultSummary struct {
Status Status
ErrorCode ErrorCode
ErrorMessage string
GasConsumed uint64
DeployedContractAddress *Address
ReturnedValue Data
Expand Down Expand Up @@ -148,12 +149,14 @@ func (res *Result) ResultSummary() *ResultSummary {

if res.Invalid() {
rs.ErrorCode = ValidationErrorCode(res.ValidationError)
rs.ErrorMessage = res.ValidationError.Error()
rs.Status = StatusInvalid
return rs
}

if res.Failed() {
rs.ErrorCode = ExecutionErrorCode(res.VMError)
rs.ErrorMessage = res.VMError.Error()
rs.Status = StatusFailed
return rs
}
Expand Down
6 changes: 3 additions & 3 deletions utils/unittest/execution_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const ServiceAccountPrivateKeySignAlgo = crypto.ECDSAP256
const ServiceAccountPrivateKeyHashAlgo = hash.SHA2_256

// Pre-calculated state commitment with root account with the above private key
const GenesisStateCommitmentHex = "eafac62c7edbd2cf1979d57f16a00d24747db3f038d8228e301437f216f6a626"
const GenesisStateCommitmentHex = "e1a25cc3003f09aa31313753fb333c039a25a3e9d3e11a3d2bef1d48567989ad"

var GenesisStateCommitment flow.StateCommitment

Expand Down Expand Up @@ -87,10 +87,10 @@ func genesisCommitHexByChainID(chainID flow.ChainID) string {
return GenesisStateCommitmentHex
}
if chainID == flow.Testnet {
return "d1a1b7b38522ab0217f67824d4661c41adb27f81dd8f425861d1f97577a34136"
return "a474d0d56d6773eadcce99982b825a79d763677081c56a89dedaf7bf6438498e"
}
if chainID == flow.Sandboxnet {
return "e1c08b17f9e5896f03fe28dd37ca396c19b26628161506924fbf785834646ea1"
}
return "73f02c37fc051ab07dc9bd2613663a8795a39aad521939ae8bae57ff844736a4"
return "6231c8864e3c71a5990d6994ece4f8655754df1e32bca1ef7bbf5a64710ffbb4"
}

0 comments on commit 0658967

Please sign in to comment.