Skip to content

Commit

Permalink
feat: add TransactionEvaluate and TransactionEvaluateUTXOs
Browse files Browse the repository at this point in the history
  • Loading branch information
slowbackspace committed Dec 3, 2023
1 parent 0d8ef23 commit 8ec8c4a
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 11 deletions.
52 changes: 52 additions & 0 deletions api_transaction_test.go

Large diffs are not rendered by default.

158 changes: 147 additions & 11 deletions api_transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ import (
)

const (
resourceTxs = "txs"
resourceTx = "tx"
resourceTxStakes = "stakes"
resourceTxUTXOs = "utxos"
resourceTxWithdrawals = "withdrawals"
resourceTxMetadata = "metadata"
resourceCbor = "cbor"
resourceTxDelegations = "delegations"
resourceTxPoolUpdates = "pool_updates"
resourceTxPoolRetires = "pool_retires"
resourceTxSubmit = "submit"
resourceTxs = "txs"
resourceTx = "tx"
resourceTxStakes = "stakes"
resourceTxUTXOs = "utxos"
resourceTxWithdrawals = "withdrawals"
resourceTxMetadata = "metadata"
resourceCbor = "cbor"
resourceTxDelegations = "delegations"
resourceTxPoolUpdates = "pool_updates"
resourceTxPoolRetires = "pool_retires"
resourceTxSubmit = "submit"
resourceTxEvaluate = "utils/txs/evaluate"
resourceTxEvaluateUtxos = "utils/txs/evaluate/utxos"
)

type TransactionContent struct {
Expand Down Expand Up @@ -274,6 +276,45 @@ type TransactionRedeemer struct {
Fee string `json:"fee"`
}

type Quantity string

type Value struct {
Coins Quantity `json:"coins"`
Assets map[string]Quantity `json:"assets,omitempty"`
}

type TxOutScript interface{} // This is an interface, actual implementation depends on usage

type TxIn struct {
TxID string `json:"txId"`
Index int `json:"index"`
}

type TxOut struct {
Address string `json:"address"`
Value Value `json:"value"`
DatumHash *string `json:"datumHash,omitempty"` // Pointer to handle null
Datum interface{} `json:"datum,omitempty"` // Could be various types
Script *TxOutScript `json:"script,omitempty"` // Pointer to handle null
}

// AdditionalUtxoSet represents a slice of tuples (TxIn, TxOut)
type AdditionalUtxoSet []struct {
TxIn TxIn `json:"txIn"`
TxOut TxOut `json:"txOut"`
}

type OgmiosResponse struct {
Type string `json:"type"`
Version string `json:"version"`
ServiceName string `json:"servicename"`
MethodName string `json:"methodname"`
Reflection struct {
Id string `json:"id"`
} `json:"reflection"`
Result json.RawMessage `json:"result"`
}

func (c *apiClient) Transaction(ctx context.Context, hash string) (tc TransactionContent, err error) {
requestUrl, err := url.Parse(fmt.Sprintf("%s/%s/%s", c.server, resourceTxs, hash))
if err != nil {
Expand Down Expand Up @@ -534,3 +575,98 @@ func (c *apiClient) TransactionSubmit(ctx context.Context, cbor []byte) (hash st
}
return hash, nil
}

// func readSubmitTx(data []byte) error {
// value, dataType, _, err := jsonparser.Get(data, "result", "SubmitFail")
// if err != nil {
// if errors.Is(err, jsonparser.KeyPathNotFoundError) {
// return nil
// }
// return fmt.Errorf("failed to parse SubmitTx response: %w", err)
// }

// switch dataType {
// case jsonparser.Array:
// var messages []json.RawMessage
// if err := json.Unmarshal(value, &messages); err != nil {
// return fmt.Errorf("failed to parse SubmitTx response: array: %w", err)
// }
// if len(messages) == 0 {
// return nil
// }
// return SubmitTxError{messages: messages}

// case jsonparser.Object:
// return SubmitTxError{messages: []json.RawMessage{value}}

// default:
// return fmt.Errorf("SubmitTx failed: %v", string(value))
// }
// }

func (c *apiClient) TransactionEvaluate(ctx context.Context, cbor []byte) (jsonResponse OgmiosResponse, err error) {
requestUrl, err := url.Parse(fmt.Sprintf("%s/%s", c.server, resourceTxEvaluate))

if err != nil {
return
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestUrl.String(), bytes.NewReader(cbor))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/cbor")
res, err := c.handleRequest(req)
if err != nil {
return
}

defer res.Body.Close()
if err = json.NewDecoder(res.Body).Decode(&jsonResponse); err != nil {
return
}
// fmt.Printf("Got response: %s", jsonResponse)
return jsonResponse, nil
}

func (c *apiClient) TransactionEvaluateUTXOs(ctx context.Context, cbor []byte, additionalUtxoSet AdditionalUtxoSet) (jsonResponse OgmiosResponse, err error) {
requestUrl, err := url.Parse(fmt.Sprintf("%s/%s", c.server, resourceTxEvaluateUtxos))
if err != nil {
return
}

// Convert addition utxo set from custom go data type (array of struct with TxIn, TxOut properties) to
// format required by the API endpoint ([[TxIn, TxOut], ...])
convertedAdditionalUtxoSet := make([][]interface{}, len(additionalUtxoSet))
for i, utxo := range additionalUtxoSet {
convertedAdditionalUtxoSet[i] = []interface{}{utxo.TxIn, utxo.TxOut}
}

payload := struct {
Cbor string `json:"cbor"`
AdditionalUtxoSet [][]interface{} `json:"additionalUtxoSet"`
}{
Cbor: string(cbor),
AdditionalUtxoSet: convertedAdditionalUtxoSet,
}

jsonData, err := json.Marshal(payload)
if err != nil {
return
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestUrl.String(), bytes.NewBuffer(jsonData))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/json")
res, err := c.handleRequest(req)
if err != nil {
return
}
defer res.Body.Close()
if err = json.NewDecoder(res.Body).Decode(&jsonResponse); err != nil {
return
}

return jsonResponse, nil
}
2 changes: 2 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,6 @@ type APIClient interface {
TransactionPoolUpdateCerts(ctx context.Context, hash string) ([]TransactionPoolCert, error)
TransactionPoolRetirementCerts(ctx context.Context, hash string) ([]TransactionPoolCert, error)
TransactionSubmit(ctx context.Context, cbor []byte) (string, error)
TransactionEvaluate(ctx context.Context, cbor []byte) (OgmiosResponse, error)
TransactionEvaluateUTXOs(ctx context.Context, cbor []byte, additionalUtxoSet AdditionalUtxoSet) (OgmiosResponse, error)
}
1 change: 1 addition & 0 deletions testdata/transactionevaluateintegration.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type":"jsonwsp/response","version":"1.0","servicename":"ogmios","methodname":"EvaluateTx","reflection":{"id":"dummy"},"result":{"EvaluationResult":{"spend:0":{"memory":1765011,"steps":503871230}}}}
1 change: 1 addition & 0 deletions testdata/transactionevaluateutxosintegration.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type":"jsonwsp/response","version":"1.0","servicename":"ogmios","methodname":"EvaluateTx","result":{"EvaluationResult":{"spend:0":{"memory":1376449,"steps":385845365}}},"reflection":{"id":"dummy"}}

0 comments on commit 8ec8c4a

Please sign in to comment.