Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XDRill ledger low level helpers example #5501

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions exp/xdrill/ledger/ledger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package ledger

import (
"encoding/base64"
"fmt"
"time"

"github.com/stellar/go/exp/xdrill/utils"
"github.com/stellar/go/xdr"
)

type Ledger struct {
xdr.LedgerCloseMeta
}

func (l Ledger) Sequence() uint32 {
return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq)

Check failure on line 17 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.LedgerHeaderHistoryEntry undefined (type Ledger has no field or method LedgerHeaderHistoryEntry) (typecheck)
}

func (l Ledger) ID() int64 {
return utils.NewID(int32(l.LedgerSequence()), 0, 0).ToInt64()

Check failure on line 21 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.LedgerSequence undefined (type Ledger has no field or method LedgerSequence) (typecheck)
}

func (l Ledger) Hash() string {
return utils.HashToHexString(l.LedgerHeaderHistoryEntry().Hash)

Check failure on line 25 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.LedgerHeaderHistoryEntry undefined (type Ledger has no field or method LedgerHeaderHistoryEntry) (typecheck)
}

func (l Ledger) PreviousHash() string {
return utils.HashToHexString(l.PreviousLedgerHash())

Check failure on line 29 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.PreviousLedgerHash undefined (type Ledger has no field or method PreviousLedgerHash) (typecheck)
}

func (l Ledger) CloseTime() int64 {
return l.LedgerCloseTime()

Check failure on line 33 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.LedgerCloseTime undefined (type Ledger has no field or method LedgerCloseTime) (typecheck)
}

func (l Ledger) ClosedAt() time.Time {
return time.Unix(l.CloseTime(), 0).UTC()
}

func (l Ledger) TotalCoins() int64 {
return int64(l.LedgerHeaderHistoryEntry().Header.TotalCoins)

Check failure on line 41 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.LedgerHeaderHistoryEntry undefined (type Ledger has no field or method LedgerHeaderHistoryEntry) (typecheck)
}

func (l Ledger) FeePool() int64 {
return int64(l.LedgerHeaderHistoryEntry().Header.FeePool)
}

func (l Ledger) BaseFee() uint32 {
return uint32(l.LedgerHeaderHistoryEntry().Header.BaseFee)
}

func (l Ledger) BaseReserve() uint32 {
return uint32(l.LedgerHeaderHistoryEntry().Header.BaseReserve)
}

func (l Ledger) MaxTxSetSize() uint32 {
return uint32(l.LedgerHeaderHistoryEntry().Header.MaxTxSetSize)
}

func (l Ledger) LedgerVersion() uint32 {
return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerVersion)
}

func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) {
lcmV1, ok := l.GetV1()

Check failure on line 65 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.GetV1 undefined (type Ledger has no field or method GetV1) (typecheck)
if ok {
extV1, ok := lcmV1.Ext.GetV1()
if ok {
return int64(extV1.SorobanFeeWrite1Kb), true
}
}

return 0, false
}

func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) {
lcmV1, ok := l.GetV1()

Check failure on line 77 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.GetV1 undefined (type Ledger has no field or method GetV1) (typecheck)
if ok {
return uint64(lcmV1.TotalByteSizeOfBucketList), true
}

return 0, false
}

func (l Ledger) NodeID() (string, bool) {
LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature()
if ok {
nodeID, ok := utils.GetAddress(LedgerCloseValueSignature.NodeId)
if ok {
return nodeID, true
}
}

return "", false
}

func (l Ledger) Signature() (string, bool) {
LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature()
if ok {
return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true
}

return "", false
}

// Add docstring to larger, more complicated functions
func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) {
transactions := getTransactionSet(l)
results := l.V0.TxProcessing

Check failure on line 109 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.V0 undefined (type Ledger has no field or method V0) (typecheck)
txCount := len(transactions)
if txCount != len(results) {
return 0, 0, false
}

for i := 0; i < txCount; i++ {
if results[i].Result.Successful() {
successTxCount++
} else {
failedTxCount++
}
}

return successTxCount, failedTxCount, true
}

// Add docstring to larger, more complicated functions
func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) {
transactions := getTransactionSet(l)
results := l.V0.TxProcessing

Check failure on line 129 in exp/xdrill/ledger/ledger.go

View workflow job for this annotation

GitHub Actions / golangci

l.V0 undefined (type Ledger has no field or method V0) (typecheck)
txCount := len(transactions)
if txCount != len(results) {
return 0, 0, false
}

for i := 0; i < txCount; i++ {
operations := transactions[i].Operations()
numberOfOps := int32(len(operations))
txSetOperationCount += numberOfOps

// for successful transactions, the operation count is based on the operations results slice
if results[i].Result.Successful() {
operationResults, ok := results[i].Result.OperationResults()
if !ok {
return 0, 0, false
}

operationCount += int32(len(operationResults))
}

}

return operationCount, txSetOperationCount, true
}

func getTransactionSet(l Ledger) (transactionProcessing []xdr.TransactionEnvelope) {
switch l.V {
case 0:
return l.V0.TxSet.Txs
case 1:
switch l.V1.TxSet.V {
case 0:
return getTransactionPhase(l.V1.TxSet.V1TxSet.Phases)
default:
panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.V1.TxSet.V))
}
default:
panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.V))
}
}

func getTransactionPhase(transactionPhase []xdr.TransactionPhase) (transactionEnvelope []xdr.TransactionEnvelope) {
transactionSlice := []xdr.TransactionEnvelope{}
for _, phase := range transactionPhase {
switch phase.V {
case 0:
components := phase.MustV0Components()
for _, component := range components {
switch component.Type {
case 0:
transactionSlice = append(transactionSlice, component.TxsMaybeDiscountedFee.Txs...)

default:
panic(fmt.Sprintf("Unsupported TxSetComponentType: %d", component.Type))
}

}
default:
panic(fmt.Sprintf("Unsupported TransactionPhase.V: %d", phase.V))
}
}

return transactionSlice
}
3 changes: 3 additions & 0 deletions exp/xdrill/ledgerentry/ledger_entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package ledgerentry

// TODO: create low level helper functions
3 changes: 3 additions & 0 deletions exp/xdrill/operation/operation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package operation

// TODO: create low level helper functions
12 changes: 12 additions & 0 deletions exp/xdrill/transaction/transaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package transaction

import (
"github.com/stellar/go/ingest"
)

type Transaction struct {
// Use ingest.LedgerTransaction to be used with TransactionReader
ingest.LedgerTransaction
}

// TODO: create low level helper functions
106 changes: 106 additions & 0 deletions exp/xdrill/transform_ledger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Note: This is placed in the xdrill directory/package just for this example
// Processors may be placed in a different location/package; To be discussed
package xdrill

import (
"fmt"
"time"

"github.com/stellar/go/exp/xdrill/ledger"
"github.com/stellar/go/xdr"
)

type LedgerClosedOutput struct {
Sequence uint32 `json:"sequence"` // sequence number of the ledger
LedgerHash string `json:"ledger_hash"`
PreviousLedgerHash string `json:"previous_ledger_hash"`
LedgerHeader string `json:"ledger_header"` // base 64 encoding of the ledger header
TransactionCount int32 `json:"transaction_count"`
OperationCount int32 `json:"operation_count"` // counts only operations that were a part of successful transactions
SuccessfulTransactionCount int32 `json:"successful_transaction_count"`
FailedTransactionCount int32 `json:"failed_transaction_count"`
TxSetOperationCount string `json:"tx_set_operation_count"` // counts all operations, even those that are part of failed transactions
ClosedAt time.Time `json:"closed_at"` // UTC timestamp
TotalCoins int64 `json:"total_coins"`
FeePool int64 `json:"fee_pool"`
BaseFee uint32 `json:"base_fee"`
BaseReserve uint32 `json:"base_reserve"`
MaxTxSetSize uint32 `json:"max_tx_set_size"`
ProtocolVersion uint32 `json:"protocol_version"`
LedgerID int64 `json:"id"`
SorobanFeeWrite1Kb int64 `json:"soroban_fee_write_1kb"`
NodeID string `json:"node_id"`
Signature string `json:"signature"`
TotalByteSizeOfBucketList uint64 `json:"total_byte_size_of_bucket_list"`
}

func TransformLedger(lcm xdr.LedgerCloseMeta) (LedgerClosedOutput, error) {
ledger := ledger.Ledger{
LedgerCloseMeta: lcm,
}

outputLedgerHeader, err := xdr.MarshalBase64(ledger.LedgerHeaderHistoryEntry().Header)
if err != nil {
return LedgerClosedOutput{}, err
}

outputSuccessfulTransactionCount, outputFailedTransactionCount, ok := ledger.TransactionCounts()
if !ok {
return LedgerClosedOutput{}, fmt.Errorf("could not get transaction counts")
}

outputOperationCount, outputTxSetOperationCount, ok := ledger.OperationCounts()
if !ok {
return LedgerClosedOutput{}, fmt.Errorf("could not get operation counts")
}

var outputSorobanFeeWrite1Kb int64
sorobanFeeWrite1Kb, ok := ledger.SorobanFeeWrite1Kb()
if ok {
outputSorobanFeeWrite1Kb = sorobanFeeWrite1Kb
}

var outputTotalByteSizeOfBucketList uint64
totalByteSizeOfBucketList, ok := ledger.TotalByteSizeOfBucketList()
if ok {
outputTotalByteSizeOfBucketList = totalByteSizeOfBucketList
}

var outputNodeID string
nodeID, ok := ledger.NodeID()
if ok {
outputNodeID = nodeID
}

var outputSigature string
signature, ok := ledger.Signature()
if ok {
outputSigature = signature
}

ledgerOutput := LedgerClosedOutput{
Sequence: ledger.LedgerSequence(),
LedgerHash: ledger.Hash(),
PreviousLedgerHash: ledger.Hash(),
LedgerHeader: outputLedgerHeader,
TransactionCount: outputSuccessfulTransactionCount,
OperationCount: outputOperationCount,
SuccessfulTransactionCount: outputSuccessfulTransactionCount,
FailedTransactionCount: outputFailedTransactionCount,
TxSetOperationCount: string(outputTxSetOperationCount),
ClosedAt: ledger.ClosedAt(),
TotalCoins: ledger.TotalCoins(),
FeePool: ledger.FeePool(),
BaseFee: ledger.BaseFee(),
BaseReserve: ledger.BaseReserve(),
MaxTxSetSize: ledger.MaxTxSetSize(),
ProtocolVersion: ledger.LedgerVersion(),
LedgerID: ledger.ID(),
SorobanFeeWrite1Kb: outputSorobanFeeWrite1Kb,
NodeID: outputNodeID,
Signature: outputSigature,
TotalByteSizeOfBucketList: outputTotalByteSizeOfBucketList,
}

return ledgerOutput, nil
}
64 changes: 64 additions & 0 deletions exp/xdrill/transform_ledger_xdr.go
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Example using helper functions only in xdr. I think for the LedgerClosed case this works really well

Type casting should be removed and just added to the functions themselves if possible

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Note: This is placed in the xdrill directory/package just for this example
// Processors may be placed in a different location/package; To be discussed
package xdrill

import (
"github.com/stellar/go/xdr"
)

func TransformLedgerXDR(lcm xdr.LedgerCloseMeta) (LedgerClosedOutput, error) {
outputLedgerHeader, err := xdr.MarshalBase64(lcm.LedgerHeaderHistoryEntry().Header)
if err != nil {
return LedgerClosedOutput{}, err
}

var outputSorobanFeeWrite1Kb int64
sorobanFeeWrite1Kb, ok := lcm.SorobanFeeWrite1Kb()
if ok {
outputSorobanFeeWrite1Kb = sorobanFeeWrite1Kb
}

var outputTotalByteSizeOfBucketList uint64
totalByteSizeOfBucketList, ok := lcm.TotalByteSizeOfBucketList()
if ok {
outputTotalByteSizeOfBucketList = totalByteSizeOfBucketList
}

var outputNodeID string
nodeID, ok := lcm.NodeID()
if ok {
outputNodeID = nodeID
}

var outputSigature string
signature, ok := lcm.Signature()
if ok {
outputSigature = signature
}

ledgerOutput := LedgerClosedOutput{
Sequence: lcm.LedgerSequence(),
LedgerHash: lcm.LedgerHash().String(),
PreviousLedgerHash: lcm.PreviousLedgerHash().String(),
LedgerHeader: outputLedgerHeader,
TransactionCount: int32(lcm.CountTransactions()),
OperationCount: int32(lcm.CountOperations()),
SuccessfulTransactionCount: int32(lcm.CountSuccessfulTransactions()),
FailedTransactionCount: int32(lcm.CountFailedTransactions()),
TxSetOperationCount: string(lcm.CountSuccessfulOperations()),

Check failure on line 48 in exp/xdrill/transform_ledger_xdr.go

View workflow job for this annotation

GitHub Actions / check (ubuntu-22.04, 1.22.1)

conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)

Check failure on line 48 in exp/xdrill/transform_ledger_xdr.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-22.04, 1.21, 12)

conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)

Check failure on line 48 in exp/xdrill/transform_ledger_xdr.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-22.04, 1.22, 12)

conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)

Check failure on line 48 in exp/xdrill/transform_ledger_xdr.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-22.04, 1.21, 16)

conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)

Check failure on line 48 in exp/xdrill/transform_ledger_xdr.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-22.04, 1.22, 16)

conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
ClosedAt: lcm.LedgerClosedAt(),
TotalCoins: lcm.TotalCoins(),
FeePool: lcm.FeePool(),
BaseFee: lcm.BaseFee(),
BaseReserve: lcm.BaseReserve(),
MaxTxSetSize: lcm.MaxTxSetSize(),
ProtocolVersion: lcm.ProtocolVersion(),
LedgerID: lcm.LedgerID(),
SorobanFeeWrite1Kb: outputSorobanFeeWrite1Kb,
NodeID: outputNodeID,
Signature: outputSigature,
TotalByteSizeOfBucketList: outputTotalByteSizeOfBucketList,
}

return ledgerOutput, nil
}
Loading
Loading