-
Notifications
You must be signed in to change notification settings - Fork 0
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 functions for ledger entry changes #3
base: 5551/xdrill-operations
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,10 @@ import ( | |
"bytes" | ||
"fmt" | ||
"sort" | ||
"time" | ||
|
||
"github.com/stellar/go/ingest/ledger" | ||
"github.com/stellar/go/ingest/ledgerentry" | ||
"github.com/stellar/go/support/errors" | ||
"github.com/stellar/go/xdr" | ||
) | ||
|
@@ -327,3 +330,128 @@ func (c Change) AccountChangedExceptSigners() (bool, error) { | |
|
||
return !bytes.Equal(preBinary, postBinary), nil | ||
} | ||
|
||
func (c Change) ExtractEntry() (xdr.LedgerEntry, xdr.LedgerEntryChangeType, bool, error) { | ||
switch changeType := c.LedgerEntryChangeType(); changeType { | ||
case xdr.LedgerEntryChangeTypeLedgerEntryCreated, xdr.LedgerEntryChangeTypeLedgerEntryUpdated: | ||
return *c.Post, changeType, false, nil | ||
case xdr.LedgerEntryChangeTypeLedgerEntryRemoved: | ||
return *c.Pre, changeType, true, nil | ||
default: | ||
return xdr.LedgerEntry{}, changeType, false, fmt.Errorf("unable to extract ledger entry type from change") | ||
} | ||
} | ||
|
||
func (c Change) Deleted() bool { | ||
return c.LedgerEntryChangeType() == xdr.LedgerEntryChangeTypeLedgerEntryRemoved | ||
} | ||
|
||
func (c Change) ClosedAt() time.Time { | ||
if c.Ledger != nil { | ||
return ledger.ClosedAt(*c.Ledger) | ||
} | ||
|
||
return ledger.ClosedAt(c.Transaction.Ledger) | ||
chowbao marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
func (c Change) Sequence() uint32 { | ||
if c.Ledger != nil { | ||
return ledger.Sequence(*c.Ledger) | ||
} | ||
|
||
return ledger.Sequence(c.Transaction.Ledger) | ||
chowbao marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
func (c Change) LastModifiedLedger() (uint32, error) { | ||
chowbao marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ledgerEntry, _, _, err := c.ExtractEntry() | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
return uint32(ledgerEntry.LastModifiedLedgerSeq), nil | ||
} | ||
|
||
func (c Change) Sponsor() (string, error) { | ||
ledgerEntry, _, _, err := c.ExtractEntry() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
if ledgerEntry.SponsoringID() == nil { | ||
return "", nil | ||
} | ||
|
||
return ledgerEntry.SponsoringID().Address(), nil | ||
} | ||
|
||
func (c Change) LedgerKeyHash() (string, error) { | ||
ledgerKey, err := c.LedgerKey() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return ledgerKey.MarshalBinaryBase64() | ||
} | ||
|
||
func (c Change) EntryDetails(passphrase string) (interface{}, error) { | ||
var err error | ||
var ledgerEntry xdr.LedgerEntry | ||
var details interface{} | ||
|
||
ledgerEntry, _, _, err = c.ExtractEntry() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
switch ledgerEntry.Data.Type { | ||
case xdr.LedgerEntryTypeAccount: | ||
details, err = ledgerentry.AccountDetails(ledgerEntry.Data.Account) | ||
if err != nil { | ||
return details, err | ||
} | ||
case xdr.LedgerEntryTypeTrustline: | ||
details, err = ledgerentry.TrustlineDetails(ledgerEntry.Data.TrustLine) | ||
if err != nil { | ||
return details, err | ||
} | ||
case xdr.LedgerEntryTypeOffer: | ||
details, err = ledgerentry.OfferDetails(ledgerEntry.Data.Offer) | ||
if err != nil { | ||
return details, err | ||
} | ||
Comment on lines
+419
to
+421
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can skip all of these checks by just returning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah makes sense. Is that good coding practice though? I thought it's generally good to return/err when it happens rather than at the end of a function. BUT these are also really small functions anyways so it's probably not a big deal There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Depends who you ask 😆 imo omitting it can show "all this function does is switch/case + parse + return" I also hate Go's pedantry for error verbosity so I like to shorten it when I can There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah just golang things 😢 |
||
case xdr.LedgerEntryTypeData: | ||
details, err = ledgerentry.DataDetails(ledgerEntry.Data.Data) | ||
if err != nil { | ||
return details, err | ||
} | ||
case xdr.LedgerEntryTypeClaimableBalance: | ||
details, err = ledgerentry.ClaimableBalanceDetails(ledgerEntry.Data.ClaimableBalance) | ||
if err != nil { | ||
return details, err | ||
} | ||
case xdr.LedgerEntryTypeLiquidityPool: | ||
details, err = ledgerentry.LiquidityPoolDetails(ledgerEntry.Data.LiquidityPool) | ||
if err != nil { | ||
return details, err | ||
} | ||
case xdr.LedgerEntryTypeContractData: | ||
details, err = ledgerentry.ContractDataDetails(passphrase, ledgerEntry.Data.ContractData) | ||
if err != nil { | ||
return details, err | ||
} | ||
case xdr.LedgerEntryTypeContractCode: | ||
details, err = ledgerentry.ContractCodeDetails(ledgerEntry.Data.ContractCode) | ||
if err != nil { | ||
return details, err | ||
} | ||
case xdr.LedgerEntryTypeTtl: | ||
details, err = ledgerentry.TtlDetails(ledgerEntry.Data.Ttl) | ||
if err != nil { | ||
return details, err | ||
} | ||
default: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: missing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did leave that off intentionally. But you're right I should just add it and make it do nothing instead of leaving it completely out |
||
return details, fmt.Errorf("unknown LedgerEntry data type") | ||
} | ||
|
||
return details, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package ledgerentry | ||
|
||
import ( | ||
"github.com/stellar/go/xdr" | ||
) | ||
|
||
type Account struct { | ||
AccountID string `json:"account_id"` | ||
Balance int64 `json:"balance"` | ||
SequenceNumber int64 `json:"sequence_number"` | ||
SequenceLedger uint32 `json:"sequence_ledger"` | ||
SequenceTime int64 `json:"sequence_time"` | ||
NumSubentries uint32 `json:"num_subentries"` | ||
Flags uint32 `json:"flags"` | ||
HomeDomain string `json:"home_domain"` | ||
MasterWeight int32 `json:"master_weight"` | ||
ThresholdLow int32 `json:"threshold_low"` | ||
ThresholdMedium int32 `json:"threshold_medium"` | ||
ThresholdHigh int32 `json:"threshold_high"` | ||
NumSponsored uint32 `json:"num_sponsored"` | ||
NumSponsoring uint32 `json:"num_sponsoring"` | ||
BuyingLiabilities int64 `json:"buying_liabilities"` | ||
SellingLiabilities int64 `json:"selling_liabilities"` | ||
InflationDestination string `json:"inflation_destination"` | ||
Signers []Signers `json:"signers"` | ||
} | ||
|
||
type Signers struct { | ||
Address string | ||
Weight int32 | ||
Sponsor string | ||
} | ||
|
||
func AccountDetails(accountEntry *xdr.AccountEntry) (Account, error) { | ||
account := Account{ | ||
AccountID: accountEntry.AccountId.Address(), | ||
SequenceNumber: int64(accountEntry.SeqNum), | ||
SequenceLedger: uint32(accountEntry.SeqLedger()), | ||
SequenceTime: int64(accountEntry.SeqTime()), | ||
NumSubentries: uint32(accountEntry.NumSubEntries), | ||
Flags: uint32(accountEntry.Flags), | ||
HomeDomain: string(accountEntry.HomeDomain), | ||
MasterWeight: int32(accountEntry.MasterKeyWeight()), | ||
ThresholdLow: int32(accountEntry.ThresholdLow()), | ||
ThresholdMedium: int32(accountEntry.ThresholdMedium()), | ||
ThresholdHigh: int32(accountEntry.ThresholdHigh()), | ||
NumSponsored: uint32(accountEntry.NumSponsored()), | ||
NumSponsoring: uint32(accountEntry.NumSponsoring()), | ||
} | ||
|
||
if accountEntry.InflationDest != nil { | ||
account.InflationDestination = accountEntry.InflationDest.Address() | ||
} | ||
|
||
accountExtensionInfo, ok := accountEntry.Ext.GetV1() | ||
if ok { | ||
account.BuyingLiabilities = int64(accountExtensionInfo.Liabilities.Buying) | ||
account.SellingLiabilities = int64(accountExtensionInfo.Liabilities.Selling) | ||
} | ||
|
||
signers := []Signers{} | ||
sponsors := accountEntry.SponsorPerSigner() | ||
for signer, weight := range accountEntry.SignerSummary() { | ||
sponsorDesc := sponsors[signer] | ||
|
||
signers = append(signers, Signers{ | ||
Address: signer, | ||
Weight: weight, | ||
Sponsor: sponsorDesc.Address(), | ||
}) | ||
} | ||
|
||
account.Signers = signers | ||
|
||
return account, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package ledgerentry | ||
|
||
import ( | ||
"github.com/stellar/go/xdr" | ||
) | ||
|
||
type ClaimableBalance struct { | ||
BalanceID string `json:"balance_id"` | ||
Claimants []Claimant `json:"claimants"` | ||
AssetCode string `json:"asset_code"` | ||
AssetIssuer string `json:"asset_issuer"` | ||
AssetType string `json:"asset_type"` | ||
AssetID int64 `json:"asset_id"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not seeing where you parse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup this is a mistake. I will drop AssetID |
||
Amount int64 `json:"amount"` | ||
Flags uint32 `json:"flags"` | ||
} | ||
|
||
type Claimant struct { | ||
Destination string `json:"destination"` | ||
Predicate xdr.ClaimPredicate `json:"predicate"` | ||
} | ||
|
||
func ClaimableBalanceDetails(claimableBalanceEntry *xdr.ClaimableBalanceEntry) (ClaimableBalance, error) { | ||
claimableBalance := ClaimableBalance{ | ||
Amount: int64(claimableBalanceEntry.Amount), | ||
Flags: uint32(claimableBalanceEntry.Flags()), | ||
} | ||
|
||
var err error | ||
var balanceID string | ||
balanceID, err = xdr.MarshalBase64(claimableBalanceEntry.BalanceId) | ||
if err != nil { | ||
return ClaimableBalance{}, err | ||
} | ||
|
||
claimableBalance.BalanceID = balanceID | ||
|
||
var assetType, assetCode, assetIssuer string | ||
err = claimableBalanceEntry.Asset.Extract(&assetType, &assetCode, &assetIssuer) | ||
if err != nil { | ||
return ClaimableBalance{}, err | ||
} | ||
|
||
claimableBalance.AssetCode = assetCode | ||
claimableBalance.AssetIssuer = assetIssuer | ||
claimableBalance.AssetType = assetType | ||
|
||
var claimants []Claimant | ||
for _, c := range claimableBalanceEntry.Claimants { | ||
switch c.Type { | ||
case 0: | ||
claimants = append(claimants, Claimant{ | ||
Destination: c.V0.Destination.Address(), | ||
Predicate: c.V0.Predicate, | ||
}) | ||
} | ||
} | ||
|
||
claimableBalance.Claimants = claimants | ||
|
||
return claimableBalance, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package ledgerentry | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/stellar/go/xdr" | ||
) | ||
|
||
type ContractCode struct { | ||
ContractCodeHash string `json:"contract_code_hash"` | ||
NInstructions uint32 `json:"n_instructions"` | ||
NFunctions uint32 `json:"n_functions"` | ||
NGlobals uint32 `json:"n_globals"` | ||
NTableEntries uint32 `json:"n_table_entries"` | ||
NTypes uint32 `json:"n_types"` | ||
NDataSegments uint32 `json:"n_data_segments"` | ||
NElemSegments uint32 `json:"n_elem_segments"` | ||
NImports uint32 `json:"n_imports"` | ||
NExports uint32 `json:"n_exports"` | ||
NDataSegmentBytes uint32 `json:"n_data_segment_bytes"` | ||
} | ||
|
||
func ContractCodeDetails(contractCodeEntry *xdr.ContractCodeEntry) (ContractCode, error) { | ||
var contractCode ContractCode | ||
|
||
switch contractCodeEntry.Ext.V { | ||
case 1: | ||
contractCode.NInstructions = uint32(contractCodeEntry.Ext.V1.CostInputs.NInstructions) | ||
contractCode.NFunctions = uint32(contractCodeEntry.Ext.V1.CostInputs.NFunctions) | ||
contractCode.NGlobals = uint32(contractCodeEntry.Ext.V1.CostInputs.NGlobals) | ||
contractCode.NTableEntries = uint32(contractCodeEntry.Ext.V1.CostInputs.NTableEntries) | ||
contractCode.NTypes = uint32(contractCodeEntry.Ext.V1.CostInputs.NTypes) | ||
contractCode.NDataSegments = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegments) | ||
contractCode.NElemSegments = uint32(contractCodeEntry.Ext.V1.CostInputs.NElemSegments) | ||
contractCode.NImports = uint32(contractCodeEntry.Ext.V1.CostInputs.NImports) | ||
contractCode.NExports = uint32(contractCodeEntry.Ext.V1.CostInputs.NExports) | ||
contractCode.NDataSegmentBytes = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegmentBytes) | ||
default: | ||
return ContractCode{}, fmt.Errorf("unknown ContractCodeEntry.Ext.V") | ||
} | ||
|
||
var err error | ||
var contractCodeHash string | ||
contractCodeHash, err = contractCodeEntry.Hash.MarshalBinaryBase64() | ||
if err != nil { | ||
return ContractCode{}, err | ||
} | ||
|
||
contractCode.ContractCodeHash = contractCodeHash | ||
|
||
return contractCode, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's also
LedgerEntryChangeTypeLedgerEntryState
which should probably be handled here instead of bailing out, no? Then noerror
case at all.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh that's good to know. I think stellar-etl code has been skipping
LedgerEntryChangeTypeLedgerEntryState
on purpose (or accidentally 😨)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the
bool
for?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ok bools are usually used to signify if the returned value is actually valid or not. And it being not valid is not an error.
For example think of soroban fees. If you want to get soroban fees for a classic transaction you'd return 0 for the fee value but also false for the bool because there is no real value for the fee
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Ideally it should be null but also
go
weirdly handles null values. So this is the way of handling it. 👍What's the reason of setting
false
bool in this case? Isn't it returning valid value?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry in this case the bool is to signify if the entry was deleted or not