raw tx binary
This commit is contained in:
234
rawtx_binary.go
234
rawtx_binary.go
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
const rawTxBinarySchemaVersionCurrent uint16 = 7
|
||||
const rawTxBinarySchemaVersionCurrent uint16 = 10
|
||||
|
||||
var rawTxBinaryMagic = [4]byte{'P', 'R', 'T', 'X'}
|
||||
var rawTxsBinaryMagic = [4]byte{'P', 'R', 'T', 'S'}
|
||||
@@ -61,11 +61,11 @@ type RawTxMetaBinary struct {
|
||||
}
|
||||
|
||||
type RawTxTokenBalanceBinary struct {
|
||||
AccountIndex uint16
|
||||
MintAccount uint16
|
||||
OwnerAccount uint16
|
||||
AccountIndex uint8
|
||||
MintAccount uint8
|
||||
OwnerAccount uint8
|
||||
HasOwnerAccount bool
|
||||
ProgramIDAccount uint16
|
||||
ProgramIDAccount uint8
|
||||
Decimals uint8
|
||||
HasPreAmount bool
|
||||
PreAmount string
|
||||
@@ -270,10 +270,17 @@ func DecodeRawTxsBinaryReader(r io.Reader) iter.Seq2[*RawTx, error] {
|
||||
}
|
||||
|
||||
func newRawTxBinaryWithAddressTable(tx *RawTx, addressTable []solana.PublicKey, addressIndex *txBinaryAddressIndex) (*RawTxBinary, error) {
|
||||
accountList := tx.getAccountList()
|
||||
accountList, err := rawTxBinaryEffectiveAccountList(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if uint64(len(accountList)) > uint64(math.MaxUint32) {
|
||||
return nil, fmt.Errorf("account list exceeds uint32 capacity")
|
||||
}
|
||||
accountListIndex, err := newRawTxBinaryAccountListIndex(accountList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if uint64(len(tx.Transaction.Message.AccountKeys)) > uint64(math.MaxUint32) {
|
||||
return nil, fmt.Errorf("message account key count exceeds uint32 capacity")
|
||||
}
|
||||
@@ -299,7 +306,7 @@ func newRawTxBinaryWithAddressTable(tx *RawTx, addressTable []solana.PublicKey,
|
||||
out.AccountList = append(out.AccountList, ref)
|
||||
}
|
||||
|
||||
meta, err := rawTxMetaToBinary(&tx.Meta, addressIndex)
|
||||
meta, err := rawTxMetaToBinary(&tx.Meta, accountListIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -520,7 +527,7 @@ func (tx *RawTxBinary) ToRawTx() (*RawTx, error) {
|
||||
IndexWithinBlock: int64(tx.IndexWithinBlock),
|
||||
Slot: tx.Slot,
|
||||
Version: rawTxBinaryVersionValue(tx.Version),
|
||||
Meta: rawTxMetaFromBinary(tx.Meta, tx.AddressTable),
|
||||
Meta: rawTxMetaFromBinary(tx.Meta, accountList),
|
||||
Transaction: rawTxTransactionFromBinary(tx.Transaction, tx.AddressTable),
|
||||
}
|
||||
if tx.AccountKeyCount > 0 && tx.AccountKeyCount <= uint32(len(accountList)) {
|
||||
@@ -678,7 +685,7 @@ func rawTxBinaryReadTxBody(dec txBinaryBodyReader, tx *RawTxBinary, addressTable
|
||||
return nil
|
||||
}
|
||||
|
||||
func rawTxMetaToBinary(meta *Meta, addressIndex *txBinaryAddressIndex) (RawTxMetaBinary, error) {
|
||||
func rawTxMetaToBinary(meta *Meta, accountListIndex map[solana.PublicKey]uint8) (RawTxMetaBinary, error) {
|
||||
out := RawTxMetaBinary{
|
||||
Err: cloneTransactionParsedError(meta.Err),
|
||||
Fee: meta.Fee,
|
||||
@@ -688,7 +695,7 @@ func rawTxMetaToBinary(meta *Meta, addressIndex *txBinaryAddressIndex) (RawTxMet
|
||||
ComputeUnitsConsumed: meta.ComputeUnitsConsumed,
|
||||
}
|
||||
var err error
|
||||
out.TokenBalances, err = rawTxTokenBalancesToBinary(meta.PreTokenBalances, meta.PostTokenBalances, addressIndex)
|
||||
out.TokenBalances, err = rawTxTokenBalancesToBinary(meta.PreTokenBalances, meta.PostTokenBalances, accountListIndex)
|
||||
if err != nil {
|
||||
return out, fmt.Errorf("token_balances: %w", err)
|
||||
}
|
||||
@@ -715,86 +722,75 @@ func rawTxMessageToBinary(message *Message, addressIndex *txBinaryAddressIndex)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func rawTxTokenBalancesToBinary(preBalances []TokenBalance, postBalances []TokenBalance, addressIndex *txBinaryAddressIndex) ([]RawTxTokenBalanceBinary, error) {
|
||||
func rawTxTokenBalancesToBinary(preBalances []TokenBalance, postBalances []TokenBalance, accountListIndex map[solana.PublicKey]uint8) ([]RawTxTokenBalanceBinary, error) {
|
||||
out := make([]RawTxTokenBalanceBinary, 0, len(preBalances)+len(postBalances))
|
||||
byAccountIndex := make(map[uint16]int, len(preBalances)+len(postBalances))
|
||||
preByAccountIndex := make(map[uint8]int, len(preBalances))
|
||||
postSeenByAccountIndex := make(map[uint8]struct{}, len(postBalances))
|
||||
for i, balance := range preBalances {
|
||||
encoded, err := rawTxTokenBalanceToBinary(balance, addressIndex)
|
||||
encoded, err := rawTxTokenBalanceToBinary(balance, accountListIndex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pre[%d]: %w", i, err)
|
||||
}
|
||||
if _, exists := byAccountIndex[encoded.AccountIndex]; exists {
|
||||
if _, exists := preByAccountIndex[encoded.AccountIndex]; exists {
|
||||
return nil, fmt.Errorf("pre[%d].account_index duplicate: %d", i, encoded.AccountIndex)
|
||||
}
|
||||
encoded.HasPreAmount = true
|
||||
encoded.PreAmount = balance.UITokenAmount.Amount
|
||||
byAccountIndex[encoded.AccountIndex] = len(out)
|
||||
preByAccountIndex[encoded.AccountIndex] = len(out)
|
||||
out = append(out, encoded)
|
||||
}
|
||||
for i, balance := range postBalances {
|
||||
encoded, err := rawTxTokenBalanceToBinary(balance, addressIndex)
|
||||
encoded, err := rawTxTokenBalanceToBinary(balance, accountListIndex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("post[%d]: %w", i, err)
|
||||
}
|
||||
if existingIndex, exists := byAccountIndex[encoded.AccountIndex]; exists {
|
||||
if out[existingIndex].HasPostAmount {
|
||||
return nil, fmt.Errorf("post[%d].account_index duplicate: %d", i, encoded.AccountIndex)
|
||||
}
|
||||
if !rawTxTokenBalanceBinarySameIdentity(out[existingIndex], encoded) {
|
||||
return nil, fmt.Errorf("post[%d].account_index %d identity mismatch", i, encoded.AccountIndex)
|
||||
}
|
||||
if _, exists := postSeenByAccountIndex[encoded.AccountIndex]; exists {
|
||||
return nil, fmt.Errorf("post[%d].account_index duplicate: %d", i, encoded.AccountIndex)
|
||||
}
|
||||
postSeenByAccountIndex[encoded.AccountIndex] = struct{}{}
|
||||
if existingIndex, exists := preByAccountIndex[encoded.AccountIndex]; exists && rawTxTokenBalanceBinarySameIdentity(out[existingIndex], encoded) {
|
||||
out[existingIndex].HasPostAmount = true
|
||||
out[existingIndex].PostAmount = balance.UITokenAmount.Amount
|
||||
continue
|
||||
}
|
||||
encoded.HasPostAmount = true
|
||||
encoded.PostAmount = balance.UITokenAmount.Amount
|
||||
byAccountIndex[encoded.AccountIndex] = len(out)
|
||||
out = append(out, encoded)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func rawTxTokenBalanceToBinary(balance TokenBalance, addressIndex *txBinaryAddressIndex) (RawTxTokenBalanceBinary, error) {
|
||||
func rawTxTokenBalanceToBinary(balance TokenBalance, accountListIndex map[solana.PublicKey]uint8) (RawTxTokenBalanceBinary, error) {
|
||||
mintAccount, ownerAccount, programIDAccount, err := rawTxBinaryTokenBalanceAccounts(balance)
|
||||
if err != nil {
|
||||
return RawTxTokenBalanceBinary{}, err
|
||||
}
|
||||
mint, err := addressIndex.id(mintAccount)
|
||||
if err != nil {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("mint: %w", err)
|
||||
mint, ok := accountListIndex[mintAccount]
|
||||
if !ok {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("mint account not found in account_list: %s", mintAccount)
|
||||
}
|
||||
programID, err := addressIndex.id(programIDAccount)
|
||||
if err != nil {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("program_id: %w", err)
|
||||
}
|
||||
if mint > math.MaxUint16 {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("mint ref overflows uint16: %d", mint)
|
||||
}
|
||||
if programID > math.MaxUint16 {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("program_id ref overflows uint16: %d", programID)
|
||||
programID, ok := accountListIndex[programIDAccount]
|
||||
if !ok {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("program_id account not found in account_list: %s", programIDAccount)
|
||||
}
|
||||
if balance.UITokenAmount.Decimals > math.MaxUint8 {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("decimals overflows uint8: %d", balance.UITokenAmount.Decimals)
|
||||
}
|
||||
if balance.AccountIndex < 0 || balance.AccountIndex > math.MaxUint16 {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("account_index overflows uint16: %d", balance.AccountIndex)
|
||||
if balance.AccountIndex < 0 || balance.AccountIndex > math.MaxUint8 {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("account_index overflows uint8: %d", balance.AccountIndex)
|
||||
}
|
||||
encoded := RawTxTokenBalanceBinary{
|
||||
AccountIndex: uint16(balance.AccountIndex),
|
||||
MintAccount: uint16(mint),
|
||||
ProgramIDAccount: uint16(programID),
|
||||
AccountIndex: uint8(balance.AccountIndex),
|
||||
MintAccount: mint,
|
||||
ProgramIDAccount: programID,
|
||||
Decimals: uint8(balance.UITokenAmount.Decimals),
|
||||
}
|
||||
if ownerAccount != nil {
|
||||
owner, err := addressIndex.id(*ownerAccount)
|
||||
if err != nil {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("owner: %w", err)
|
||||
owner, ok := accountListIndex[*ownerAccount]
|
||||
if !ok {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("owner account not found in account_list: %s", *ownerAccount)
|
||||
}
|
||||
if owner > math.MaxUint16 {
|
||||
return RawTxTokenBalanceBinary{}, fmt.Errorf("owner ref overflows uint16: %d", owner)
|
||||
}
|
||||
encoded.OwnerAccount = uint16(owner)
|
||||
encoded.OwnerAccount = owner
|
||||
encoded.HasOwnerAccount = true
|
||||
}
|
||||
return encoded, nil
|
||||
@@ -809,8 +805,8 @@ func rawTxTokenBalanceBinarySameIdentity(a, b RawTxTokenBalanceBinary) bool {
|
||||
a.Decimals == b.Decimals
|
||||
}
|
||||
|
||||
func rawTxMetaFromBinary(meta RawTxMetaBinary, addressTable []solana.PublicKey) Meta {
|
||||
preTokenBalances, postTokenBalances := rawTxTokenBalancesFromBinary(meta.TokenBalances, addressTable)
|
||||
func rawTxMetaFromBinary(meta RawTxMetaBinary, accountList []solana.PublicKey) Meta {
|
||||
preTokenBalances, postTokenBalances := rawTxTokenBalancesFromBinary(meta.TokenBalances, accountList)
|
||||
return Meta{
|
||||
Err: cloneTransactionParsedError(meta.Err),
|
||||
Fee: meta.Fee,
|
||||
@@ -838,15 +834,15 @@ func rawTxTransactionFromBinary(tx RawTxTransactionBinary, addressTable []solana
|
||||
return out
|
||||
}
|
||||
|
||||
func rawTxTokenBalancesFromBinary(balances []RawTxTokenBalanceBinary, addressTable []solana.PublicKey) ([]TokenBalance, []TokenBalance) {
|
||||
func rawTxTokenBalancesFromBinary(balances []RawTxTokenBalanceBinary, accountList []solana.PublicKey) ([]TokenBalance, []TokenBalance) {
|
||||
pre := make([]TokenBalance, 0, len(balances))
|
||||
post := make([]TokenBalance, 0, len(balances))
|
||||
for _, balance := range balances {
|
||||
mint, _ := txBinaryAddressAt(addressTable, uint32(balance.MintAccount), "token_balance.mint")
|
||||
programID, _ := txBinaryAddressAt(addressTable, uint32(balance.ProgramIDAccount), "token_balance.program_id")
|
||||
mint, _ := txBinaryAddressAt(accountList, uint32(balance.MintAccount), "token_balance.mint")
|
||||
programID, _ := txBinaryAddressAt(accountList, uint32(balance.ProgramIDAccount), "token_balance.program_id")
|
||||
var owner *solana.PublicKey
|
||||
if balance.HasOwnerAccount {
|
||||
ownerKey, _ := txBinaryAddressAt(addressTable, uint32(balance.OwnerAccount), "token_balance.owner")
|
||||
ownerKey, _ := txBinaryAddressAt(accountList, uint32(balance.OwnerAccount), "token_balance.owner")
|
||||
owner = &ownerKey
|
||||
}
|
||||
if balance.HasPreAmount {
|
||||
@@ -1065,10 +1061,10 @@ func readInnerInstructions(dec txBinaryBodyReader) ([]InnerInstructions, error)
|
||||
func writeInstructions(enc *txBinaryEncoder, values []Instruction) error {
|
||||
enc.writeUint32(uint32(len(values)))
|
||||
for i, value := range values {
|
||||
if value.ProgramIDIndex < 0 || value.ProgramIDIndex > math.MaxUint16 {
|
||||
return fmt.Errorf("[%d].program_id_index overflows uint16: %d", i, value.ProgramIDIndex)
|
||||
if value.ProgramIDIndex < 0 || value.ProgramIDIndex > math.MaxUint8 {
|
||||
return fmt.Errorf("[%d].program_id_index overflows uint8: %d", i, value.ProgramIDIndex)
|
||||
}
|
||||
enc.writeUint16(uint16(value.ProgramIDIndex))
|
||||
enc.writeUint8(uint8(value.ProgramIDIndex))
|
||||
if err := writeAccountIndexSlice(enc, value.Accounts); err != nil {
|
||||
return fmt.Errorf("[%d].accounts: %w", i, err)
|
||||
}
|
||||
@@ -1077,6 +1073,10 @@ func writeInstructions(enc *txBinaryEncoder, values []Instruction) error {
|
||||
if value.StackHeight != nil {
|
||||
enc.writeUint32(uint32(*value.StackHeight))
|
||||
}
|
||||
enc.writeUint32(uint32(len(value.LogEvents)))
|
||||
for _, event := range value.LogEvents {
|
||||
writeByteSlice(enc, event)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1088,7 +1088,7 @@ func readInstructions(dec txBinaryBodyReader) ([]Instruction, error) {
|
||||
}
|
||||
out := make([]Instruction, 0, count)
|
||||
for i := uint32(0); i < count; i++ {
|
||||
programIDIndex, err := dec.readUint16()
|
||||
programIDIndex, err := dec.readUint8()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1113,11 +1113,24 @@ func readInstructions(dec txBinaryBodyReader) ([]Instruction, error) {
|
||||
sh := int(rawStackHeight)
|
||||
stackHeight = &sh
|
||||
}
|
||||
logEventCount, err := dec.readUint32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logEvents := make([]solana.Base64, 0, logEventCount)
|
||||
for j := uint32(0); j < logEventCount; j++ {
|
||||
eventData, err := readByteSlice(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logEvents = append(logEvents, solana.Base64(eventData))
|
||||
}
|
||||
out = append(out, Instruction{
|
||||
ProgramIDIndex: int(programIDIndex),
|
||||
Accounts: accounts,
|
||||
Data: solana.Base58(data),
|
||||
StackHeight: stackHeight,
|
||||
LogEvents: logEvents,
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
@@ -1126,13 +1139,13 @@ func readInstructions(dec txBinaryBodyReader) ([]Instruction, error) {
|
||||
func writeTokenBalances(enc *txBinaryEncoder, values []RawTxTokenBalanceBinary) error {
|
||||
enc.writeUint32(uint32(len(values)))
|
||||
for i, value := range values {
|
||||
enc.writeUint16(value.AccountIndex)
|
||||
enc.writeUint16(value.MintAccount)
|
||||
enc.writeUint8(value.AccountIndex)
|
||||
enc.writeUint8(value.MintAccount)
|
||||
enc.writeBool(value.HasOwnerAccount)
|
||||
if value.HasOwnerAccount {
|
||||
enc.writeUint16(value.OwnerAccount)
|
||||
enc.writeUint8(value.OwnerAccount)
|
||||
}
|
||||
enc.writeUint16(value.ProgramIDAccount)
|
||||
enc.writeUint8(value.ProgramIDAccount)
|
||||
enc.writeUint8(value.Decimals)
|
||||
enc.writeBool(value.HasPreAmount)
|
||||
if value.HasPreAmount {
|
||||
@@ -1158,21 +1171,21 @@ func readTokenBalances(dec txBinaryBodyReader) ([]RawTxTokenBalanceBinary, error
|
||||
out := make([]RawTxTokenBalanceBinary, 0, count)
|
||||
for i := uint32(0); i < count; i++ {
|
||||
value := RawTxTokenBalanceBinary{}
|
||||
if value.AccountIndex, err = dec.readUint16(); err != nil {
|
||||
if value.AccountIndex, err = dec.readUint8(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if value.MintAccount, err = dec.readUint16(); err != nil {
|
||||
if value.MintAccount, err = dec.readUint8(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if value.HasOwnerAccount, err = dec.readBool(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if value.HasOwnerAccount {
|
||||
if value.OwnerAccount, err = dec.readUint16(); err != nil {
|
||||
if value.OwnerAccount, err = dec.readUint8(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if value.ProgramIDAccount, err = dec.readUint16(); err != nil {
|
||||
if value.ProgramIDAccount, err = dec.readUint8(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if value.Decimals, err = dec.readUint8(); err != nil {
|
||||
@@ -1336,10 +1349,10 @@ func readUint32Slice(dec txBinaryBodyReader) ([]uint32, error) {
|
||||
func writeAccountIndexSlice(enc *txBinaryEncoder, values []int) error {
|
||||
enc.writeUint32(uint32(len(values)))
|
||||
for i, value := range values {
|
||||
if value < 0 || value > math.MaxUint16 {
|
||||
return fmt.Errorf("[%d] overflows uint16: %d", i, value)
|
||||
if value < 0 || value > math.MaxUint8 {
|
||||
return fmt.Errorf("[%d] overflows uint8: %d", i, value)
|
||||
}
|
||||
enc.writeUint16(uint16(value))
|
||||
enc.writeUint8(uint8(value))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1351,7 +1364,7 @@ func readAccountIndexSlice(dec txBinaryBodyReader) ([]int, error) {
|
||||
}
|
||||
out := make([]int, 0, count)
|
||||
for i := uint32(0); i < count; i++ {
|
||||
value, err := dec.readUint16()
|
||||
value, err := dec.readUint8()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1547,7 +1560,11 @@ func rawTxBinaryBuildAddressTable(txs []*RawTx) ([]solana.PublicKey, error) {
|
||||
if tx == nil {
|
||||
return nil, fmt.Errorf("tx[%d] is nil", txIndex)
|
||||
}
|
||||
for accountIndex, account := range tx.getAccountList() {
|
||||
accountList, err := rawTxBinaryEffectiveAccountList(tx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tx[%d].account_list: %w", txIndex, err)
|
||||
}
|
||||
for accountIndex, account := range accountList {
|
||||
if err := builder.add(account); err != nil {
|
||||
return nil, fmt.Errorf("tx[%d].account_list[%d]: %w", txIndex, accountIndex, err)
|
||||
}
|
||||
@@ -1557,20 +1574,64 @@ func rawTxBinaryBuildAddressTable(txs []*RawTx) ([]solana.PublicKey, error) {
|
||||
return nil, fmt.Errorf("tx[%d].address_table_lookups[%d].account_key: %w", txIndex, lookupIndex, err)
|
||||
}
|
||||
}
|
||||
for balanceIndex, balance := range tx.Meta.PreTokenBalances {
|
||||
if err := rawTxBinaryAddTokenBalanceAddresses(&builder, balance); err != nil {
|
||||
return nil, fmt.Errorf("tx[%d].pre_token_balances[%d]: %w", txIndex, balanceIndex, err)
|
||||
}
|
||||
}
|
||||
for balanceIndex, balance := range tx.Meta.PostTokenBalances {
|
||||
if err := rawTxBinaryAddTokenBalanceAddresses(&builder, balance); err != nil {
|
||||
return nil, fmt.Errorf("tx[%d].post_token_balances[%d]: %w", txIndex, balanceIndex, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.addresses, nil
|
||||
}
|
||||
|
||||
func rawTxBinaryEffectiveAccountList(tx *RawTx) ([]solana.PublicKey, error) {
|
||||
accountList := append([]solana.PublicKey(nil), tx.getAccountList()...)
|
||||
seen := make(map[solana.PublicKey]struct{}, len(accountList))
|
||||
for _, account := range accountList {
|
||||
seen[account] = struct{}{}
|
||||
}
|
||||
for balanceIndex, balance := range tx.Meta.PreTokenBalances {
|
||||
if err := rawTxBinaryAppendTokenBalanceAccounts(&accountList, seen, balance); err != nil {
|
||||
return nil, fmt.Errorf("pre_token_balances[%d]: %w", balanceIndex, err)
|
||||
}
|
||||
}
|
||||
for balanceIndex, balance := range tx.Meta.PostTokenBalances {
|
||||
if err := rawTxBinaryAppendTokenBalanceAccounts(&accountList, seen, balance); err != nil {
|
||||
return nil, fmt.Errorf("post_token_balances[%d]: %w", balanceIndex, err)
|
||||
}
|
||||
}
|
||||
return accountList, nil
|
||||
}
|
||||
|
||||
func rawTxBinaryAppendTokenBalanceAccounts(accountList *[]solana.PublicKey, seen map[solana.PublicKey]struct{}, balance TokenBalance) error {
|
||||
mintAccount, ownerAccount, programIDAccount, err := rawTxBinaryTokenBalanceAccounts(balance)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawTxBinaryAppendAccountIfMissing(accountList, seen, mintAccount)
|
||||
if ownerAccount != nil {
|
||||
rawTxBinaryAppendAccountIfMissing(accountList, seen, *ownerAccount)
|
||||
}
|
||||
rawTxBinaryAppendAccountIfMissing(accountList, seen, programIDAccount)
|
||||
return nil
|
||||
}
|
||||
|
||||
func rawTxBinaryAppendAccountIfMissing(accountList *[]solana.PublicKey, seen map[solana.PublicKey]struct{}, account solana.PublicKey) {
|
||||
if _, exists := seen[account]; exists {
|
||||
return
|
||||
}
|
||||
seen[account] = struct{}{}
|
||||
*accountList = append(*accountList, account)
|
||||
}
|
||||
|
||||
func newRawTxBinaryAccountListIndex(accountList []solana.PublicKey) (map[solana.PublicKey]uint8, error) {
|
||||
out := make(map[solana.PublicKey]uint8, len(accountList))
|
||||
for i, account := range accountList {
|
||||
if i > math.MaxUint8 {
|
||||
return nil, fmt.Errorf("account_list index overflows uint8: %d", i)
|
||||
}
|
||||
if _, exists := out[account]; exists {
|
||||
continue
|
||||
}
|
||||
out[account] = uint8(i)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func rawTxBinarySharedBlockTime(txs []*RawTx, field string) (int64, error) {
|
||||
if len(txs) == 0 {
|
||||
return 0, nil
|
||||
@@ -1672,6 +1733,7 @@ func cloneInstructions(values []Instruction) []Instruction {
|
||||
Accounts: append([]int(nil), value.Accounts...),
|
||||
Data: append(solana.Base58(nil), value.Data...),
|
||||
ProgramIDIndex: value.ProgramIDIndex,
|
||||
LogEvents: cloneBase64Slice(value.LogEvents),
|
||||
}
|
||||
if value.StackHeight != nil {
|
||||
stackHeight := *value.StackHeight
|
||||
@@ -1682,6 +1744,14 @@ func cloneInstructions(values []Instruction) []Instruction {
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneBase64Slice(values []solana.Base64) []solana.Base64 {
|
||||
out := make([]solana.Base64, 0, len(values))
|
||||
for _, value := range values {
|
||||
out = append(out, append(solana.Base64(nil), value...))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func rawTxBinaryVersionID(version interface{}) uint8 {
|
||||
switch value := version.(type) {
|
||||
case solana.MessageVersion:
|
||||
|
||||
Reference in New Issue
Block a user