278 lines
8.3 KiB
Go
278 lines
8.3 KiB
Go
package pump_parser
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
)
|
|
|
|
type TransactionErrorVariant uint32
|
|
type InstructionErrorVariant uint32
|
|
|
|
type InstructionErrorEnum struct {
|
|
Index uint8
|
|
Variant InstructionErrorVariant
|
|
rest []byte
|
|
}
|
|
|
|
type CustomInstructionErrorEnum struct {
|
|
Code uint32
|
|
}
|
|
|
|
const (
|
|
AccountInUse TransactionErrorVariant = iota
|
|
AccountLoadedTwice
|
|
AccountNotFound
|
|
ProgramAccountNotFound
|
|
InsufficientFundsForFee
|
|
InvalidAccountForFee
|
|
AlreadyProcessed
|
|
BlockhashNotFound
|
|
|
|
InstructionError //InstructionError(u8, InstructionError),
|
|
|
|
CallChainTooDeep
|
|
MissingSignatureForFee
|
|
InvalidAccountIndex
|
|
SignatureFailure
|
|
InvalidProgramForExecution
|
|
SanitizeFailure
|
|
ClusterMaintenance
|
|
AccountBorrowOutstanding
|
|
WouldExceedMaxBlockCostLimit
|
|
UnsupportedVersion
|
|
InvalidWritableAccount
|
|
WouldExceedMaxAccountCostLimit
|
|
WouldExceedAccountDataBlockLimit
|
|
TooManyAccountLocks
|
|
AddressLookupTableNotFound
|
|
InvalidAddressLookupTableOwner
|
|
InvalidAddressLookupTableData
|
|
InvalidAddressLookupTableIndex
|
|
InvalidRentPayingAccount
|
|
WouldExceedMaxVoteCostLimit
|
|
WouldExceedAccountDataTotalLimit
|
|
|
|
DuplicateInstruction //DuplicateInstruction(u8),
|
|
|
|
/*
|
|
InsufficientFundsForRent {
|
|
account_index: u8,
|
|
},
|
|
*/
|
|
InsufficientFundsForRent
|
|
|
|
MaxLoadedAccountsDataSizeExceeded
|
|
InvalidLoadedAccountsDataSizeLimit
|
|
ResanitizationNeeded
|
|
|
|
/*
|
|
ProgramExecutionTemporarilyRestricted {
|
|
account_index: u8,
|
|
},
|
|
*/
|
|
ProgramExecutionTemporarilyRestricted
|
|
|
|
UnbalancedTransaction
|
|
ProgramCacheHitMaxLimit
|
|
CommitCancelled
|
|
)
|
|
|
|
const (
|
|
GenericError InstructionErrorVariant = iota
|
|
/// The arguments provided to a program were invalid
|
|
InvalidArgument
|
|
/// An instruction's data contents were invalid
|
|
InvalidInstructionData
|
|
/// An account's data contents was invalid
|
|
InvalidAccountData
|
|
/// An account's data was too small
|
|
AccountDataTooSmall
|
|
/// An account's balance was too small to complete the instruction
|
|
InsufficientFunds
|
|
/// The account did not have the expected program id
|
|
IncorrectProgramId
|
|
/// A signature was required but not found
|
|
MissingRequiredSignature
|
|
/// An initialize instruction was sent to an account that has already been initialized.
|
|
AccountAlreadyInitialized
|
|
/// An attempt to operate on an account that hasn't been initialized.
|
|
UninitializedAccount
|
|
/// Program's instruction lamport balance does not equal the balance after the instruction
|
|
UnbalancedInstruction
|
|
/// Program illegally modified an account's program id
|
|
ModifiedProgramId
|
|
/// Program spent the lamports of an account that doesn't belong to it
|
|
ExternalAccountLamportSpend
|
|
/// Program modified the data of an account that doesn't belong to it
|
|
ExternalAccountDataModified
|
|
/// Read-only account's lamports modified
|
|
ReadonlyLamportChange
|
|
/// Read-only account's data was modified
|
|
ReadonlyDataModified
|
|
/// An account was referenced more than once in a single instruction
|
|
// Deprecated, instructions can now contain duplicate accounts
|
|
DuplicateAccountIndex
|
|
/// Executable bit on account changed, but shouldn't have
|
|
ExecutableModified
|
|
/// Rent_epoch account changed, but shouldn't have
|
|
RentEpochModified
|
|
/// The instruction expected additional account keys
|
|
NotEnoughAccountKeys
|
|
/// Program other than the account's owner changed the size of the account data
|
|
AccountDataSizeChanged
|
|
/// The instruction expected an executable account
|
|
AccountNotExecutable
|
|
/// Failed to borrow a reference to account data, already borrowed
|
|
AccountBorrowFailed
|
|
/// Account data has an outstanding reference after a program's execution
|
|
InstructionAccountBorrowOutstanding
|
|
/// The same account was multiply passed to an on-chain program's entrypoint, but the program
|
|
/// modified them differently. A program can only modify one instance of the account because
|
|
/// the runtime cannot determine which changes to pick or how to merge them if both are modified
|
|
DuplicateAccountOutOfSync
|
|
/// Allows on-chain programs to implement program-specific error types and see them returned
|
|
/// by the Solana runtime. A program-specific error may be any type that is represented as
|
|
/// or serialized to a u32 integer.
|
|
|
|
Custom // Custom(u32),
|
|
|
|
/// The return value from the program was invalid. Valid errors are either a defined builtin
|
|
/// error value or a user-defined error in the lower 32 bits.
|
|
InvalidError
|
|
/// Executable account's data was modified
|
|
ExecutableDataModified
|
|
/// Executable account's lamports modified
|
|
ExecutableLamportChange
|
|
/// Executable accounts must be rent exempt
|
|
ExecutableAccountNotRentExempt
|
|
/// Unsupported program id
|
|
UnsupportedProgramId
|
|
/// Cross-program invocation call depth too deep
|
|
CallDepth
|
|
/// An account required by the instruction is missing
|
|
MissingAccount
|
|
/// Cross-program invocation reentrancy not allowed for this instruction
|
|
ReentrancyNotAllowed
|
|
/// Length of the seed is too long for address generation
|
|
MaxSeedLengthExceeded
|
|
/// Provided seeds do not result in a valid address
|
|
InvalidSeeds
|
|
/// Failed to reallocate account data of this length
|
|
InvalidRealloc
|
|
/// Computational budget exceeded
|
|
ComputationalBudgetExceeded
|
|
/// Cross-program invocation with unauthorized signer or writable account
|
|
PrivilegeEscalation
|
|
/// Failed to create program execution environment
|
|
ProgramEnvironmentSetupFailure
|
|
/// Program failed to complete
|
|
ProgramFailedToComplete
|
|
/// Program failed to compile
|
|
ProgramFailedToCompile
|
|
/// Account is immutable
|
|
Immutable
|
|
/// Incorrect authority provided
|
|
IncorrectAuthority
|
|
/// Failed to serialize or deserialize account data
|
|
///
|
|
/// Warning: This error should never be emitted by the runtime.
|
|
///
|
|
/// This error includes strings from the underlying 3rd party Borsh crate
|
|
/// which can be dangerous because the error strings could change across
|
|
/// Borsh versions. Only programs can use this error because they are
|
|
/// consistent across Solana software versions.
|
|
/// string values from this error should not be used in
|
|
|
|
BorshIoError // BorshIoError(String)
|
|
|
|
// An account does not have enough lamports to be rent-exempt
|
|
AccountNotRentExempt
|
|
/// Invalid account owner
|
|
InvalidAccountOwner
|
|
/// Program arithmetic overflowed
|
|
ArithmeticOverflow
|
|
/// Unsupported sysvar
|
|
UnsupportedSysvar
|
|
/// Illegal account owner
|
|
IllegalOwner
|
|
/// Accounts data allocations exceeded the maximum allowed per transaction
|
|
MaxAccountsDataAllocationsExceeded
|
|
/// Max accounts exceeded
|
|
MaxAccountsExceeded
|
|
/// Max instruction trace length exceeded
|
|
MaxInstructionTraceLengthExceeded
|
|
/// Builtin programs must consume compute units
|
|
BuiltinProgramsMustConsumeComputeUnits
|
|
)
|
|
|
|
type TransactionError struct {
|
|
Variant TransactionErrorVariant
|
|
rest []byte
|
|
}
|
|
|
|
var (
|
|
ErrInvalidTransactionError = errors.New("invalid transaction error")
|
|
NotAnInstructionError = errors.New("not an instruction error")
|
|
NotACustomInstructionError = errors.New("not a custom instruction error")
|
|
UnsupportedInstructionError = errors.New("unsupported instruction error")
|
|
)
|
|
|
|
func DecodeTransactionError(data []byte) (*TransactionError, error) {
|
|
if len(data) < 4 {
|
|
return nil, ErrInvalidTransactionError
|
|
}
|
|
|
|
var err TransactionError
|
|
variant := binary.LittleEndian.Uint32(data[:4])
|
|
if variant > uint32(CommitCancelled) {
|
|
return nil, UnsupportedInstructionError
|
|
}
|
|
err.Variant = TransactionErrorVariant(variant)
|
|
err.rest = data[4:]
|
|
|
|
return &err, nil
|
|
}
|
|
|
|
func (e *TransactionError) GetCustomErrorCode() (uint8, uint32, error) {
|
|
instr, err := e.GetInstructionError()
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
custom, err := instr.Custom()
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return instr.Index, custom.Code, nil
|
|
}
|
|
|
|
func (e *TransactionError) GetInstructionError() (*InstructionErrorEnum, error) {
|
|
if e.Variant != InstructionError {
|
|
return nil, NotAnInstructionError
|
|
}
|
|
if len(e.rest) < 5 {
|
|
return nil, NotAnInstructionError
|
|
}
|
|
|
|
var err InstructionErrorEnum
|
|
err.Index = e.rest[0]
|
|
variant := binary.LittleEndian.Uint32(e.rest[1:5])
|
|
if variant > uint32(BuiltinProgramsMustConsumeComputeUnits) {
|
|
return nil, UnsupportedInstructionError
|
|
}
|
|
err.Variant = InstructionErrorVariant(binary.LittleEndian.Uint32(e.rest[1:5]))
|
|
err.rest = e.rest[5:]
|
|
return &err, nil
|
|
}
|
|
|
|
func (e *InstructionErrorEnum) Custom() (*CustomInstructionErrorEnum, error) {
|
|
if e.Variant != Custom {
|
|
return nil, NotACustomInstructionError
|
|
}
|
|
if len(e.rest) < 4 {
|
|
return nil, NotACustomInstructionError
|
|
}
|
|
var custom CustomInstructionErrorEnum
|
|
custom.Code = binary.LittleEndian.Uint32(e.rest[:4])
|
|
return &custom, nil
|
|
}
|