Skip to content

wip:add write capability#654

Open
Krish-vemula wants to merge 18 commits into
mainfrom
feat/stellar-write-capability
Open

wip:add write capability#654
Krish-vemula wants to merge 18 commits into
mainfrom
feat/stellar-write-capability

Conversation

@Krish-vemula

Copy link
Copy Markdown

No description provided.

@Krish-vemula Krish-vemula force-pushed the feat/stellar-write-capability branch from 4196e56 to 053c462 Compare June 15, 2026 12:27
@Krish-vemula Krish-vemula marked this pull request as ready for review June 22, 2026 13:41
@Krish-vemula Krish-vemula requested review from a team as code owners June 22, 2026 13:41
@Krish-vemula Krish-vemula requested a review from ilija42 June 22, 2026 13:41

@ilija42 ilija42 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still reviewing, but there are missing features here that need to be implemented, so I will flag that in this initial review so that you can continue working on this

Comment thread chain_capabilities/stellar/actions/write_report.go Outdated
Comment thread chain_capabilities/stellar/actions/actions.go
Comment thread chain_capabilities/stellar/actions/write_report.go Outdated
Comment thread chain_capabilities/stellar/actions/write_report.go Outdated
Comment thread chain_capabilities/stellar/actions/write_report.go Outdated
Comment thread chain_capabilities/stellar/actions/write_report.go Outdated
@Krish-vemula Krish-vemula requested a review from ilija42 June 25, 2026 09:23

@ilija42 ilija42 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build is failing and test CI is red

@Krish-vemula Krish-vemula requested a review from ilija42 June 25, 2026 13:56
Comment thread chain_capabilities/stellar/actions/forwarder_client.go Outdated
Comment thread chain_capabilities/stellar/actions/forwarder_client.go Outdated
@cl-sonarqube-production

Copy link
Copy Markdown

@Krish-vemula Krish-vemula requested a review from ilija42 June 28, 2026 12:23

@ilija42 ilija42 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some comments

Comment on lines +115 to +120
args, err := buildTransmissionInfoArgs(receiver, workflowExecutionID, reportID)
if err != nil {
return TransmissionInfo{}, err
}

resp, err := fc.SimulateTransaction(ctx, stellartypes.SimulateTransactionRequest{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at the already established pattern with the EVM forwarder codec. Handling all the encoding/decoding in one place helps us isolate the concerns, ideally you always want to have stable APIs behind cohesive abstractions, this makes the code easier to understand and simpler to test.

Comment on lines +111 to +113
receiver string,
workflowExecutionID [32]byte,
reportID [2]byte,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge this into a TransmissionID struct, this makes enriching logs simpler as well as makes the code easier to understand

return nil, err
}

rawReportVal := stellartypes.ScVal{Type: stellartypes.ScValTypeBytes, Bytes: report.GetRawReport()}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are nil and empty slice treated the same, do these args need to be sanitized?

return info, nil
}

func parseFieldsIntoTransmissionInfo(info *TransmissionInfo, sv xdr.ScVal) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This decoding should be stricter, we know exactly what the contract returns, this almost reads like a generic parse, instead we want light weight decoding so that we don't even need to rely on a generated contract client

Comment on lines +337 to +343
func observedWriteReportResult(reply *stellarcap.WriteReportReply) writeReportExecuteResult {
return writeReportExecuteResult{response: reply, billNode: false}
}

func submittedWriteReportResult(reply *stellarcap.WriteReportReply) writeReportExecuteResult {
return writeReportExecuteResult{response: reply, billNode: true}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These helpers are not needed if we just return billing metadata from the execute itself, its a bit more straightforward and follows the established pattern

transmissionScheduler ts.TransmissionScheduler
}

type writeReportExecuteResult struct {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets follow the established evm pattern of how the reply is built, I'm finding it a bit hard to follow it here, no need to delegate billing decision

@ilija42 ilija42 requested a review from yashnevatia June 29, 2026 17:22
reportID,
)

info, err := wr.pollTransmissionInfo(ctx, request.ContractId, workflowExecutionID, reportID, queuePosition)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be an optimisation here if we simulate the tx and see that it fails we just skip the polling too. There are some edge cases here though, what if the simulation fails only on some of the node and how do we ensure same reply across the DON? I wouldn't block this PR because of it, but at least add a TODO and lets think about this as a followup

switch postInfo.State {
case TransmissionStateSucceeded:
reply := wr.successReplyFromObservedState(postInfo)
populateReplyFromSubmit(reply, submitResp)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Node1 submits TX, and Node2 sends duplicate TX (because of lagging RPC for instance), Node2's TX will revert onchain, however with populateReplyFromSubmit we will return Node2's TX hash.
EVM Handles it by GetSuccessfulTransmissionHash logic, which retrieves the transaction that actually delivered successful transmission, and its proven to be a useful guard from returning non-identical responses.
Is there any Stellar-related quirks that is stopping us from reusing EVM (and Solana) logic of populating reply with successful transaction hash?

reply := wr.revertedReplyFromObservedState(postInfo, "receiver contract execution failed")
populateReplyFromSubmit(reply, submitResp)
return submittedWriteReportResult(reply), nil
default:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle unkown status and return error instead of silent fallback (same as EVM/Aptos/Solana)?

return submittedWriteReportResult(reply), nil
case TransmissionStateInvalidReceiver:
reply := wr.revertedReplyFromObservedState(postInfo, "receiver contract cannot accept reports: not a Wasm contract or missing on_report function")
populateReplyFromSubmit(reply, submitResp)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, we need to ensure we returned the same TxHash Across all the nodes like EVM/Solana do

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants