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 for ledgerCloseMeta #5568

Merged
merged 14 commits into from
Jan 21, 2025
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() {
chowbao marked this conversation as resolved.
Show resolved Hide resolved
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()))
}
Loading