Files
pump-parser/example/geyser/error.go

278 lines
8.3 KiB
Go
Raw Normal View History

2025-11-20 17:56:45 +08:00
package geyser
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
}