Parallel Universe
  • Learn
    • Introduction to PUT
    • Getting started with PUT
  • Architecture
    • What is a PUT Cluster?
    • Clusters
      • PUT Clusters
      • RPC Endpoints
      • Benchmark a Cluster
      • Performance Metrics
    • Consensus
      • Synchronization
      • Leader Rotation
      • Fork Generation
      • Managing Forks
      • Turbine Block Propagation
      • Commitment Status
      • Secure Vote Signing
      • Stake Delegation and Rewards
    • Validators
      • Overview
      • TPU
      • TVU
      • Blockstore
      • Gossip Service
      • The Runtime
  • CLI
    • Command-line Guide
    • Install the PUT Tool Suite
    • Command-line Wallets
      • Command Line Wallets
      • Paper Wallet
      • File System Wallet
      • Support / Troubleshooting
    • Using PUT CLI
    • Connecting to a Cluster
    • Send and Receive Tokens
    • Staking
    • Deploy a Program
    • Offline Transaction Signing
    • Durable Transaction Nonces
    • CLI Usage Reference
  • Developers
    • Get Started
      • Hello World
      • Local development
      • Rust program
    • Core Concepts
      • Accounts
      • Transactions
        • Overview
        • Versioned Transactions
        • Address Lookup Tables
      • Programs
      • Rent
      • Calling between programs
      • Runtime
    • Clients
      • JSON RPC API -1
      • JSON RPC API -2
      • JSON RPC API -3
      • Web3 JavaScript API
      • Web3 API Reference
      • Rust API
    • Writing Programs
      • Overview
      • Developing with Rust
      • Deploying
      • Debugging
      • Program Examples
      • FAQ
    • Native Programs
      • Overview
      • Sysvar Cluster Data
    • Local Development
      • PUT Test Validator
    • Backward Compatibility Policy
  • Validators
    • Running a Validator
    • Getting Started
      • Validator Requirements
    • Voting Setup
      • Starting a Validator
      • Vote Account Management
      • Staking
      • Monitoring a Validator
      • Publishing Validator Info
      • Failover Setup
      • Troubleshooting
    • Geyser
      • Geyser Plugins
  • Staking
    • Staking on PUT
    • Stake Account Structure
  • Integrations
    • Add PUT to Your Exchange
    • Retrying Transactions
  • Library
    • Introduction
    • Token Program
    • Associated Token Account Program
    • Memo Program
    • Name Service
    • Feature Proposal Program
    • NFT Program
      • Overview
      • Interface
      • Usage Guidelines
        • Create a new NFT-Mint
        • Cast NFT
        • Transfer an NFT
        • Change account status
        • Permission settings
        • Query Interface
        • Continuous casting
        • Change the Mint attribute
      • Operation Overview
        • Create a new NFT-Mint
        • Transfer NFT
        • Destroy
        • Freeze NFT accounts
        • Update
    • PUT multi-sign program
      • Overview
      • Interface
      • Usage Guidelines
        • Create a multi-signature account
        • Create a proposal account
        • Vote proposal
        • Verify Proposal
        • Add-singer
        • Remove-signer
      • Operation Overview
        • Create a multi-signature account
        • Create a proposal account
        • Vote
        • Verify
        • Add-singer
        • Remove-signer
  • PUT Privacy Policy
Powered by GitBook
On this page
  • Running unit tests
  • Logging
  • Error Handling
  • Monitoring Compute Budget Consumption
  • ELF Dump
  • Instruction Tracing
  1. Developers
  2. Writing Programs

Debugging

Debugging Programs

PUT programs run on-chain, so debugging them in the wild can be challenging. To make debugging programs easier, developers can write unit tests that directly test their program's execution via the PUT runtime, or run a local cluster that will allow RPC clients to interact with their program.

Running unit tests

Testing with Rust

Logging

During program execution both the runtime and the program log status and error messages.

For information about how to log from a program see the language specific documentation:

Logging from a Rust program

When running a local cluster the logs are written to stdout as long as they are enabled via the RUST_LOG log mask. From the perspective of program development it is helpful to focus on just the runtime and program logs and not the rest of the cluster logs. To focus in on program specific information the following log mask is recommended:

export RUST_LOG=put_runtime::system_instruction_processor=trace,put_runtime::message_processor=info,put_bpf_loader=debug,put_rbpf=debug

Log messages coming directly from the program (not the runtime) will be displayed in the form:

Program log:

Error Handling

The amount of information that can be communicated via a transaction error is limited but there are many points of possible failures. The following are possible failure points and information about what errors to expect and where to get more information:

The BPF loader may fail to parse the program, this should not happen since the loader has already finalized the program's account data.
    InstructionError::InvalidAccountData will be returned as part of the transaction error.
The BPF loader may fail to setup the program's execution environment
    InstructionError::Custom(0x0b9f_0001) will be returned as part of the transaction error. "0x0b9f_0001" is the hexadecimal representation of VirtualMachineCreationFailed.
The BPF loader may have detected a fatal error during program executions (things like panics, memory violations, system call errors, etc...)
    InstructionError::Custom(0x0b9f_0002) will be returned as part of the transaction error. "0x0b9f_0002" is the hexadecimal representation of VirtualMachineFailedToRunProgram.
The program itself may return an error
    InstructionError::Custom(<user defined value>) will be returned. The "user defined value" must not conflict with any of the builtin runtime program errors. Programs typically use enumeration types to define error codes starting at zero so they won't conflict.

In the case of VirtualMachineFailedToRunProgram errors, more information about the specifics of what failed are written to the program's execution logs.

For example, an access violation involving the stack will look something like this:

BPF program 4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM failed: out of bounds memory store (insn #615), addr 0x200001e38/8

Monitoring Compute Budget Consumption

The program can log the remaining number of compute units it will be allowed before program execution is halted. Programs can use these logs to wrap operations they wish to profile.

Log the remaining compute units from a Rust program

See compute budget for more information.

ELF Dump

The BPF shared object internals can be dumped to a text file to gain more insight into a program's composition and what it may be doing at runtime.

Create a dump file of a Rust program

Instruction Tracing

During execution the runtime BPF interpreter can be configured to log a trace message for each BPF instruction executed. This can be very helpful for things like pin-pointing the runtime context leading up to a memory access violation.

The trace logs together with the ELF dump can provide a lot of insight (though the traces produce a lot of information).

To turn on BPF interpreter trace messages in a local cluster configure the put_rbpf level in RUST_LOG to trace. For example:

export RUST_LOG=put_rbpf=trace

PreviousDeployingNextProgram Examples

Last updated 2 years ago