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 2 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
1 change: 1 addition & 0 deletions exp/xdrill/ledgerentries/ledger_entries.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package ledgerentries
193 changes: 193 additions & 0 deletions exp/xdrill/ledgers/ledgers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package ledgers

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

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

type Ledgers struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be singular,Ledger, all the receiver methods imply such.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah that's a good catch. I'll make the packages, structs, and functions all singular instead of plural

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated in 3b90190

xdr.LedgerCloseMeta
}

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

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

View workflow job for this annotation

GitHub Actions / golangci

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

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

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

View workflow job for this annotation

GitHub Actions / golangci

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

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

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

View workflow job for this annotation

GitHub Actions / golangci

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

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

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

View workflow job for this annotation

GitHub Actions / golangci

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

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

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

View workflow job for this annotation

GitHub Actions / golangci

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

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

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

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

View workflow job for this annotation

GitHub Actions / golangci

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

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

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

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

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

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

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

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

View workflow job for this annotation

GitHub Actions / golangci

l.GetV1 undefined (type Ledgers 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 Ledgers) TotalByteSizeOfBucketList() (uint64, bool) {
lcmV1, ok := l.GetV1()

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

View workflow job for this annotation

GitHub Actions / golangci

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

return 0, false
}

func (l Ledgers) 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 Ledgers) 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 Ledgers) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) {
transactions := getTransactionSet(l)
results := l.V0.TxProcessing

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

View workflow job for this annotation

GitHub Actions / golangci

l.V0 undefined (type Ledgers 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 Ledgers) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) {
transactions := getTransactionSet(l)
results := l.V0.TxProcessing

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

View workflow job for this annotation

GitHub Actions / golangci

l.V0 undefined (type Ledgers 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 Ledgers) (transactionProcessing []xdr.TransactionEnvelope) {
Copy link
Contributor

@sreuland sreuland Nov 4, 2024

Choose a reason for hiding this comment

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

would this be where new layer can reference the new non-xdr model instead, i.e. returning a []transactions.Transactions ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That wasn't the intent of this function. This was just carryover from stellar-etl to count the transactions/operations.

I think you're right though that it would be nice to include a function for users to call to get the non-xdr model instead of manually doing it

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
}
1 change: 1 addition & 0 deletions exp/xdrill/operations/operations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package operations
9 changes: 9 additions & 0 deletions exp/xdrill/transactions/transactions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package transactions

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

type Transactions struct {
ingest.LedgerTransaction
}
104 changes: 104 additions & 0 deletions exp/xdrill/transform_ledger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package xdrill

import (
"fmt"
"time"

"github.com/stellar/go/exp/xdrill/ledgers"
"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 := ledgers.Ledgers{
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
}
Loading
Loading