Skip to content

Commit

Permalink
xdrill for ledgerCloseMeta (#5568)
Browse files Browse the repository at this point in the history
  • Loading branch information
chowbao authored Jan 21, 2025
1 parent bd7c1ad commit 07d197a
Show file tree
Hide file tree
Showing 5 changed files with 384 additions and 0 deletions.
143 changes: 143 additions & 0 deletions ingest/ledger/ledger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package ledger

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

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

func Sequence(l xdr.LedgerCloseMeta) uint32 {
return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq)
}

func Hash(l xdr.LedgerCloseMeta) string {
return l.LedgerHeaderHistoryEntry().Hash.HexString()
}

func PreviousHash(l xdr.LedgerCloseMeta) string {
return l.PreviousLedgerHash().HexString()
}

func CloseTime(l xdr.LedgerCloseMeta) int64 {
return l.LedgerCloseTime()
}

func ClosedAt(l xdr.LedgerCloseMeta) time.Time {
return time.Unix(l.LedgerCloseTime(), 0).UTC()
}

func TotalCoins(l xdr.LedgerCloseMeta) int64 {
return int64(l.LedgerHeaderHistoryEntry().Header.TotalCoins)
}

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

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

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

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

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

func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) (int64, bool) {
lcmV1, ok := l.GetV1()
if !ok {
return 0, false
}

extV1, ok := lcmV1.Ext.GetV1()
if !ok {
return 0, false
}

return int64(extV1.SorobanFeeWrite1Kb), true
}

func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) {
lcmV1, ok := l.GetV1()
if !ok {
return 0, false
}

return uint64(lcmV1.TotalByteSizeOfBucketList), true
}

func NodeID(l xdr.LedgerCloseMeta) (string, error) {
LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature()
if !ok {
return "", fmt.Errorf("could not get LedgerCloseValueSignature")

}
return LedgerCloseValueSignature.NodeId.GetAddress()
}

func Signature(l xdr.LedgerCloseMeta) (string, bool) {
LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature()
if !ok {
return "", false
}

return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true
}

// TransactionCounts calculates and returns the number of successful and total transactions
func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, totalTxCount uint32) {
transactions := l.TransactionEnvelopes()
results, err := l.TxProcessing()
if err != nil {
panic(err)
}

txCount := len(transactions)
if txCount != len(results) {
panic("transaction count and number of TransactionResultMeta not equal")
}

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

return successTxCount, uint32(txCount)
}

// OperationCounts calculates and returns the number of successful operations and the total operations within
// a LedgerCloseMeta
func OperationCounts(l xdr.LedgerCloseMeta) (successfulOperationCount, totalOperationCount uint32) {
transactions := l.TransactionEnvelopes()
results, err := l.TxProcessing()
if err != nil {
panic(err)
}

for i, result := range results {
operations := transactions[i].OperationsCount()
totalOperationCount += operations

// for successful transactions, the operation count is based on the operations results slice
if result.Result.Successful() {
operationResults, ok := result.Result.OperationResults()
if !ok {
panic("could not get OperationResults")
}

successfulOperationCount += uint32(len(operationResults))
}
}

return successfulOperationCount, totalOperationCount
}
199 changes: 199 additions & 0 deletions ingest/ledger/ledger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package ledger

import (
"testing"
"time"

"github.com/stellar/go/keypair"
"github.com/stellar/go/txnbuild"
"github.com/stellar/go/xdr"
"github.com/stretchr/testify/assert"
)

func TestLedger(t *testing.T) {
ledger := ledgerTestInput()

assert.Equal(t, uint32(30578981), Sequence(ledger))
assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger))
assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", PreviousHash(ledger))
assert.Equal(t, int64(1594584547), CloseTime(ledger))
assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ClosedAt(ledger))
assert.Equal(t, int64(1054439020873472865), TotalCoins(ledger))
assert.Equal(t, int64(18153766209161), FeePool(ledger))
assert.Equal(t, uint32(100), BaseFee(ledger))
assert.Equal(t, uint32(5000000), BaseReserve(ledger))
assert.Equal(t, uint32(1000), MaxTxSetSize(ledger))
assert.Equal(t, uint32(13), LedgerVersion(ledger))

var ok bool
var freeWrite int64
freeWrite, ok = SorobanFeeWrite1Kb(ledger)
assert.Equal(t, true, ok)
assert.Equal(t, int64(12), freeWrite)

var bucketSize uint64
bucketSize, ok = TotalByteSizeOfBucketList(ledger)
assert.Equal(t, true, ok)
assert.Equal(t, uint64(56), bucketSize)

var nodeID string
var err error
nodeID, err = NodeID(ledger)
assert.Equal(t, nil, err)
assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID)

var signature string
signature, ok = Signature(ledger)
assert.Equal(t, true, ok)
assert.Equal(t, "9g==", signature)

var success uint32
var total uint32
success, total = TransactionCounts(ledger)
assert.Equal(t, uint32(1), success)
assert.Equal(t, uint32(2), total)

success, total = OperationCounts(ledger)
assert.Equal(t, uint32(1), success)
assert.Equal(t, uint32(13), total)
}

func ledgerTestInput() (lcm xdr.LedgerCloseMeta) {
lcm = xdr.LedgerCloseMeta{
V: 1,
V1: &xdr.LedgerCloseMetaV1{
Ext: xdr.LedgerCloseMetaExt{
V: 1,
V1: &xdr.LedgerCloseMetaExtV1{
SorobanFeeWrite1Kb: xdr.Int64(12),
},
},
LedgerHeader: xdr.LedgerHeaderHistoryEntry{
Hash: xdr.Hash{0x26, 0x93, 0x2d, 0xc4, 0xd8, 0x4b, 0x5f, 0xab, 0xe9, 0xae, 0x74, 0x4c, 0xb4, 0x3c, 0xe4, 0xc6, 0xda, 0xcc, 0xf9, 0x8c, 0x86, 0xa9, 0x91, 0xb2, 0xa1, 0x49, 0x45, 0xb1, 0xad, 0xac, 0x4d, 0x59},
Header: xdr.LedgerHeader{
LedgerSeq: 30578981,
TotalCoins: 1054439020873472865,
FeePool: 18153766209161,
BaseFee: 100,
BaseReserve: 5000000,
MaxTxSetSize: 1000,
LedgerVersion: 13,
PreviousLedgerHash: xdr.Hash{0xf6, 0x3c, 0x15, 0xd0, 0xea, 0xf4, 0x8a, 0xfb, 0xd7, 0x51, 0xa4, 0xc4, 0xdf, 0xad, 0xe5, 0x4a, 0x34, 0x48, 0x5, 0x3c, 0x47, 0xc5, 0xa7, 0x1d, 0x62, 0x26, 0x68, 0xae, 0xc, 0xc2, 0xa2, 0x8},
ScpValue: xdr.StellarValue{
Ext: xdr.StellarValueExt{
V: 1,
LcValueSignature: &xdr.LedgerCloseValueSignature{
NodeId: xdr.NodeId{
Type: 0,
Ed25519: &xdr.Uint256{34},
},
Signature: []byte{0xf6},
},
},
CloseTime: 1594584547,
},
},
},
TotalByteSizeOfBucketList: xdr.Uint64(56),
TxSet: xdr.GeneralizedTransactionSet{
V: 0,
V1TxSet: &xdr.TransactionSetV1{
Phases: []xdr.TransactionPhase{
{
V: 0,
V0Components: &[]xdr.TxSetComponent{
{
Type: 0,
TxsMaybeDiscountedFee: &xdr.TxSetComponentTxsMaybeDiscountedFee{
Txs: []xdr.TransactionEnvelope{
createSampleTx(3),
createSampleTx(10),
},
},
},
},
},
},
},
},
TxProcessing: []xdr.TransactionResultMeta{
{
Result: xdr.TransactionResultPair{
Result: xdr.TransactionResult{
Result: xdr.TransactionResultResult{
Code: xdr.TransactionResultCodeTxSuccess,
Results: &[]xdr.OperationResult{
{
Code: xdr.OperationResultCodeOpInner,
Tr: &xdr.OperationResultTr{
Type: xdr.OperationTypeCreateAccount,
CreateAccountResult: &xdr.CreateAccountResult{
Code: 0,
},
},
},
},
},
},
},
},
{
Result: xdr.TransactionResultPair{
Result: xdr.TransactionResult{
Result: xdr.TransactionResultResult{
Code: xdr.TransactionResultCodeTxFailed,
Results: &[]xdr.OperationResult{
{
Code: xdr.OperationResultCodeOpInner,
Tr: &xdr.OperationResultTr{
Type: xdr.OperationTypeCreateAccount,
CreateAccountResult: &xdr.CreateAccountResult{
Code: 0,
},
},
},
},
},
},
},
},
},
},
}

return lcm
}

func createSampleTx(operationCount int) xdr.TransactionEnvelope {
kp, err := keypair.Random()
panicOnError(err)

operations := []txnbuild.Operation{}
operationType := &txnbuild.BumpSequence{
BumpTo: 0,
}
for i := 0; i < operationCount; i++ {
operations = append(operations, operationType)
}

sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0))
tx, err := txnbuild.NewTransaction(
txnbuild.TransactionParams{
SourceAccount: &sourceAccount,
Operations: operations,
BaseFee: txnbuild.MinBaseFee,
Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()},
},
)
panicOnError(err)

env := tx.ToXDR()
return env
}

// PanicOnError is a function that panics if the provided error is not nil
func panicOnError(err error) {
if err != nil {
panic(err)
}
}
12 changes: 12 additions & 0 deletions xdr/ledger_close_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,15 @@ func (l LedgerCloseMeta) EvictedPersistentLedgerEntries() ([]LedgerEntry, error)
panic(fmt.Sprintf("Unsupported LedgerCloseMeta.V: %d", l.V))
}
}

// TxProcessing returns the TransactionResultMeta in this ledger
func (l LedgerCloseMeta) TxProcessing() ([]TransactionResultMeta, error) {
switch l.V {
case 0:
return l.MustV0().TxProcessing, nil
case 1:
return l.MustV1().TxProcessing, nil
default:
return []TransactionResultMeta{}, fmt.Errorf("Unsupported LedgerCloseMeta.V: %d", l.V)
}
}
26 changes: 26 additions & 0 deletions xdr/node_id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package xdr

import (
"fmt"

"github.com/stellar/go/strkey"
)

func (n NodeId) GetAddress() (string, error) {
switch n.Type {
case PublicKeyTypePublicKeyTypeEd25519:
ed, ok := n.GetEd25519()
if !ok {
return "", fmt.Errorf("could not get NodeID.Ed25519")
}
raw := make([]byte, 32)
copy(raw, ed[:])
encodedAddress, err := strkey.Encode(strkey.VersionByteAccountID, raw)
if err != nil {
return "", err
}
return encodedAddress, nil
default:
return "", fmt.Errorf("unknown NodeId.PublicKeyType")
}
}
4 changes: 4 additions & 0 deletions xdr/transaction_envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,7 @@ func (e TransactionEnvelope) Memo() Memo {
panic("unsupported transaction type: " + e.Type.String())
}
}

func (e TransactionEnvelope) OperationsCount() uint32 {
return uint32(len(e.Operations()))
}

0 comments on commit 07d197a

Please sign in to comment.