From 417adf0c4123674cfa25934a79204ebe4f756314 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 1 Apr 2026 20:31:57 +0100 Subject: [PATCH] fix: accept deployed aptos write reply wire layout --- capabilities/blockchain/aptos/client_sdk.go | 129 ++++++++++++------ .../blockchain/aptos/client_sdk_test.go | 29 ++++ 2 files changed, 114 insertions(+), 44 deletions(-) diff --git a/capabilities/blockchain/aptos/client_sdk.go b/capabilities/blockchain/aptos/client_sdk.go index 8d52bd76..f6dc16a4 100644 --- a/capabilities/blockchain/aptos/client_sdk.go +++ b/capabilities/blockchain/aptos/client_sdk.go @@ -1,4 +1,3 @@ - // Capability ID: aptos:ChainSelector:@1.0.0, method "View". package aptos @@ -100,6 +99,8 @@ func (c *Client) View(runtime cre.Runtime, input *ViewRequest) cre.Promise[*View // decodeWriteReportReply decodes capabilities.blockchain.aptos.v1alpha.WriteReportReply // via protobuf wire parsing to avoid runtime reflection panics under WASM. +// It accepts both the currently deployed Aptos capability wire layout and the +// newer SDK layout for receiver_contract_execution_status during rollout. func decodeWriteReportReply(b []byte) (*WriteReportReply, error) { out := &WriteReportReply{} for len(b) > 0 { @@ -119,50 +120,90 @@ func decodeWriteReportReply(b []byte) (*WriteReportReply, error) { } out.TxStatus = TxStatus(v) b = b[m:] - case 2: // receiver_contract_execution_status enum (varint) - if typ != protowire.VarintType { - return nil, fmt.Errorf("decode WriteReportReply.receiver_contract_execution_status: unexpected wire type %d", typ) - } - v, m := protowire.ConsumeVarint(b) - if m < 0 { - return nil, fmt.Errorf("decode WriteReportReply.receiver_contract_execution_status varint: %v", protowire.ParseError(m)) - } - status := ReceiverContractExecutionStatus(v) - out.ReceiverContractExecutionStatus = &status - b = b[m:] - case 3: // tx_hash string - if typ != protowire.BytesType { - return nil, fmt.Errorf("decode WriteReportReply.tx_hash: unexpected wire type %d", typ) - } - v, m := protowire.ConsumeBytes(b) - if m < 0 { - return nil, fmt.Errorf("decode WriteReportReply.tx_hash bytes: %v", protowire.ParseError(m)) - } - txHash := string(v) - out.TxHash = &txHash - b = b[m:] - case 4: // transaction_fee varint - if typ != protowire.VarintType { - return nil, fmt.Errorf("decode WriteReportReply.transaction_fee: unexpected wire type %d", typ) - } - v, m := protowire.ConsumeVarint(b) - if m < 0 { - return nil, fmt.Errorf("decode WriteReportReply.transaction_fee varint: %v", protowire.ParseError(m)) - } - fee := uint64(v) - out.TransactionFee = &fee - b = b[m:] - case 5: // error_message string - if typ != protowire.BytesType { - return nil, fmt.Errorf("decode WriteReportReply.error_message: unexpected wire type %d", typ) - } - v, m := protowire.ConsumeBytes(b) - if m < 0 { - return nil, fmt.Errorf("decode WriteReportReply.error_message bytes: %v", protowire.ParseError(m)) + case 2: // deployed layout: tx_hash string; newer layout: receiver status enum + switch typ { + case protowire.BytesType: + v, m := protowire.ConsumeBytes(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.tx_hash bytes: %v", protowire.ParseError(m)) + } + txHash := string(v) + out.TxHash = &txHash + b = b[m:] + case protowire.VarintType: + v, m := protowire.ConsumeVarint(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.receiver_contract_execution_status varint: %v", protowire.ParseError(m)) + } + status := ReceiverContractExecutionStatus(v) + out.ReceiverContractExecutionStatus = &status + b = b[m:] + default: + return nil, fmt.Errorf("decode WriteReportReply field 2: unexpected wire type %d", typ) + } + case 3: // deployed layout: transaction_fee varint; newer layout: tx_hash string + switch typ { + case protowire.VarintType: + v, m := protowire.ConsumeVarint(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.transaction_fee varint: %v", protowire.ParseError(m)) + } + fee := uint64(v) + out.TransactionFee = &fee + b = b[m:] + case protowire.BytesType: + v, m := protowire.ConsumeBytes(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.tx_hash bytes: %v", protowire.ParseError(m)) + } + txHash := string(v) + out.TxHash = &txHash + b = b[m:] + default: + return nil, fmt.Errorf("decode WriteReportReply field 3: unexpected wire type %d", typ) + } + case 4: // deployed layout: error_message string; newer layout: transaction_fee varint + switch typ { + case protowire.BytesType: + v, m := protowire.ConsumeBytes(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.error_message bytes: %v", protowire.ParseError(m)) + } + msg := string(v) + out.ErrorMessage = &msg + b = b[m:] + case protowire.VarintType: + v, m := protowire.ConsumeVarint(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.transaction_fee varint: %v", protowire.ParseError(m)) + } + fee := uint64(v) + out.TransactionFee = &fee + b = b[m:] + default: + return nil, fmt.Errorf("decode WriteReportReply field 4: unexpected wire type %d", typ) + } + case 5: // deployed layout: receiver status enum; newer layout: error_message string + switch typ { + case protowire.VarintType: + v, m := protowire.ConsumeVarint(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.receiver_contract_execution_status varint: %v", protowire.ParseError(m)) + } + status := ReceiverContractExecutionStatus(v) + out.ReceiverContractExecutionStatus = &status + b = b[m:] + case protowire.BytesType: + v, m := protowire.ConsumeBytes(b) + if m < 0 { + return nil, fmt.Errorf("decode WriteReportReply.error_message bytes: %v", protowire.ParseError(m)) + } + msg := string(v) + out.ErrorMessage = &msg + b = b[m:] + default: + return nil, fmt.Errorf("decode WriteReportReply field 5: unexpected wire type %d", typ) } - msg := string(v) - out.ErrorMessage = &msg - b = b[m:] default: m := protowire.ConsumeFieldValue(num, typ, b) if m < 0 { diff --git a/capabilities/blockchain/aptos/client_sdk_test.go b/capabilities/blockchain/aptos/client_sdk_test.go index 1b657964..5b0a79ee 100644 --- a/capabilities/blockchain/aptos/client_sdk_test.go +++ b/capabilities/blockchain/aptos/client_sdk_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/proto" ) @@ -34,3 +35,31 @@ func TestDecodeWriteReportReply_NewWireShape(t *testing.T) { require.NotNil(t, reply.ErrorMessage) require.Equal(t, errMsg, *reply.ErrorMessage) } + +func TestDecodeWriteReportReply_DeployedWireShape(t *testing.T) { + t.Parallel() + + var replyBytes []byte + replyBytes = protowire.AppendTag(replyBytes, 1, protowire.VarintType) + replyBytes = protowire.AppendVarint(replyBytes, uint64(TxStatus_TX_STATUS_ABORTED)) + replyBytes = protowire.AppendTag(replyBytes, 2, protowire.BytesType) + replyBytes = protowire.AppendString(replyBytes, "0xabc123") + replyBytes = protowire.AppendTag(replyBytes, 3, protowire.VarintType) + replyBytes = protowire.AppendVarint(replyBytes, 42) + replyBytes = protowire.AppendTag(replyBytes, 4, protowire.BytesType) + replyBytes = protowire.AppendString(replyBytes, "receiver execution failed") + replyBytes = protowire.AppendTag(replyBytes, 5, protowire.VarintType) + replyBytes = protowire.AppendVarint(replyBytes, uint64(ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED)) + + reply, err := decodeWriteReportReply(replyBytes) + require.NoError(t, err) + require.Equal(t, TxStatus_TX_STATUS_ABORTED, reply.TxStatus) + require.NotNil(t, reply.ReceiverContractExecutionStatus) + require.Equal(t, ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED, *reply.ReceiverContractExecutionStatus) + require.NotNil(t, reply.TxHash) + require.Equal(t, "0xabc123", *reply.TxHash) + require.NotNil(t, reply.TransactionFee) + require.Equal(t, uint64(42), *reply.TransactionFee) + require.NotNil(t, reply.ErrorMessage) + require.Equal(t, "receiver execution failed", *reply.ErrorMessage) +}