A program deployment makes executable code available; invoking its instructions creates or changes separate application state. This walkthrough uses the Anchor 1.1.2 counter starter, validates initialize and increment through a local RPC client, then shows the explicit devnet deployment and client path.
Understand what this counter will do
The starter has two instructions. initialize creates a counter account, sets count to zero and records the payer as authority. increment checks that authority and raises the count until the configured maximum.
The current multiple-file starter uses the seed bytes counter to derive one state PDA under the program ID. It is one shared counter for this starter program, not a new independent counter for every wallet.
The first initializer becomes its recorded authority. Subsequent increments require that authority's signature. This makes checking the actual state important before running the client against an existing deployment.
The template also demonstrates a System Program CPI which transfers one extra lamport from the payer to the counter during initialization. That is separate from required account funding and transaction fees.
Prepare compatible tools and a development-only wallet
Install the development tools through the current official installation guide linked below and inspect the installer before running it. This walkthrough targets the Anchor 1.1.2 multiple-file LiteSVM starter, with Agave CLI 4.4.1 and its compatible SBF build path.
rustc --version
solana --version
anchor --version
node --versionUse a separate directory and a fresh development keypair. The following creation command prompts for recovery protection; keep the key file and recovery material private. Never commit them or reuse a wallet containing mainnet assets.
mkdir solanabull-lab
cd solanabull-lab
solana-keygen new --outfile devnet-wallet.json
anchor init solanabull-counter --no-git --no-install --test-template litesvm
cd solanabull-counterThe wallet file sits outside the generated program directory. That placement reduces accidental inclusion in a source archive, but still requires appropriate local file protection.
Read the account constraints before building
Open programs/solanabull-counter/src. lib.rs exposes the instruction handlers and program ID. constants.rs defines the PDA seed, extra one-lamport transfer and maximum count of ten.
The initialize account context requires a signing writable payer, initializes the expected PDA with funded space and includes the System Program. Its handler stores count and authority, then makes the transfer CPI.
The increment context requires the expected writable counter and a signing authority. The handler compares the supplied authority with the stored value and checks count against the maximum before adding one.
Those checks perform different jobs: deterministic address, valid account data, signing permission, intended relationship and allowed value range. Understanding them makes later errors diagnosable.
Read the starter’s 48-byte counter account
Build the current SBF artifact
cargo build-sbf --manifest-path programs/solanabull-counter/Cargo.toml --tools-version v1.57 --arch v3This invokes the builder directly with explicit platform tools and SBPFv3. It avoids the older platform-tools pin used by this Anchor CLI. Current Anza guidance distinguishes compiler support from deployment eligibility on a cluster.
The compiled artifact is target/deploy/solanabull_counter.so. Keep the generated Cargo.lock with your project and record the resolved dependencies. The checked project resolved anchor-lang 1.2.2 from the starter's compatible version range.
The verification below uses a local validator and the downloadable client. It checks the actual account after each instruction through RPC. The generated LiteSVM test is a separate harness; these steps do not depend on its older runtime accepting this SBPFv3 artifact.
Use your generated program ID consistently
solana address -k target/deploy/solanabull_counter-keypair.jsonThe returned public address identifies your program. Keep it consistent with declare_id! in lib.rs and the generated deployment configuration. Do not copy another tutorial's ID.
The program keypair and development payer are different files with different roles. Preserve the actual generated keypair for the initial deployment; do not publish its contents in an example bundle.
If you regenerate or synchronize IDs, rebuild before deployment. The PDA depends on the program ID, so another program ID also changes the expected counter address.
Deploy on a local validator first
From the program directory, start a separate local cluster in one terminal. The ledger path belongs to this exercise; keep this process running while using a second terminal for deployment.
solana-test-validator --ledger ../local-ledger --rpc-port 18899 --faucet-port 19900 --bind-address 127.0.0.1 --quietIn the second terminal, return to the same program directory. Fund the development payer with local test SOL and deploy the compiled code explicitly to that local endpoint.
solana airdrop 10 --url http://127.0.0.1:18899 --keypair ../devnet-wallet.json
solana program deploy target/deploy/solanabull_counter.so \
--program-id target/deploy/solanabull_counter-keypair.json \
--url http://127.0.0.1:18899 --keypair ../devnet-wallet.json --use-rpcThese are local test balances. Deployment can involve a buffer and several transactions. Save the public program ID and output, and keep any recovery material private if an interrupted deployment prints it.
Deployment stores executable code. It has not yet initialized the counter. The next step supplies the program instructions and verifies their resulting state.
Invoke the counter and read the accepted state
Deployment alone does not initialize the counter. Use an instruction-building client with the exact starter's account order, discriminators, PDA and signatures.
Download the SolanaBull counter client into a separate client directory beside your project. It uses a pinned web3.js 3.2.0 SDK and legacy transactions, which are separate from the availability of newer transaction formats.
mkdir ../client
cd ../client
npm init -y
npm install @solana/web3.js@3.2.0
# Save invoke-counter.mjs here from the download above.
node invoke-counter.mjs ../devnet-wallet.json YOUR_PROGRAM_ID http://127.0.0.1:18899Replace YOUR_PROGRAM_ID with your generated public ID. The client permits the public devnet endpoint or an explicit localhost test endpoint, reads the wallet file locally and prints public identities and resulting transaction signatures.
It derives the counter PDA and initializes it if absent. It verifies the owner, account discriminator, 48-byte layout, count zero and expected authority, then increments and reads the accepted state again. A fresh run should end at count one.
On a repeated run, it reads the existing state and increments from that value. It rejects another authority or a counter already at ten. It does not reset an existing counter by pretending initialization can run again.
Repeat the deployment on devnet when funded
Public devnet has separate balances and state. Request free test funding through the supported faucet or CLI, then check the actual balance before deploying.
solana airdrop 2 --url devnet --keypair ../devnet-wallet.json
solana balance --url devnet --keypair ../devnet-wallet.json
solana program deploy target/deploy/solanabull_counter.so \
--program-id target/deploy/solanabull_counter-keypair.json \
--url devnet --keypair ../devnet-wallet.json --use-rpcRun these commands from the program directory. The requested two test SOL are an example faucet request, not a guaranteed grant or deployment-cost estimate. If the faucet rejects it, continue local testing or follow its current official instructions.
From the client directory, run node invoke-counter.mjs ../devnet-wallet.json YOUR_PROGRAM_ID to use the client's default public devnet endpoint. Replace the program ID as before. Inspect the actual devnet program and counter, because the local counter is a different account state on a different cluster.
The editorial check on 7 November 2026 verified build, local deployment and RPC initialization/increment. The public devnet faucet rejected funding, so no public devnet deployment is claimed for that check.
Use the failing stage to find the problem
A build architecture error concerns tool compatibility. A faucet rejection concerns test funding. Deployment failure concerns code storage and delivery. An authority error during increment concerns the counter's stored relationship.
For a successful client call, inspect the real transaction and resulting state on the same cluster. A Memo log or local test success from another program is not evidence that this counter executed on devnet.
Keep versions, artifact identity, cluster, program ID, public transaction records and assertions with your exercise notes. Local execution and public devnet deployment are separate verification milestones.
Extend the starter with tests for a wrong authority, a repeated initialize and the maximum count before building a larger application. The counter teaches account and instruction mechanics; production programs need their own design and security review.
Common questions
Does the starter create one counter per user?
This version uses a constant counter seed under the program ID, so it creates one shared counter for that program. A per-user design needs an explicit user-scoped seed and authorization model.
Does deploying call initialize?
No. Deployment stores executable code. A separate instruction invocation initializes application state.
Why does the example call the SBF builder directly?
The explicit v1.57 tools and SBPFv3 architecture avoid the older Anchor CLI’s platform-tools pin. Verify the target cluster’s current deployment rules and keep the versions together.
Can I keep incrementing forever?
The starter checks its configured maximum of ten and the recorded authority. The client checks those conditions before submitting.
Sources and documentation
- Solana: current Anchor starter walkthrough
- Solana: development-tool installation
- Solana: deploying programs
- Solana: deployment and upgrade authority
- Solana program derived addresses
- Solana cross-program invocations
- getAccountInfo
- Solana transactions
- Anza: SBF platform tools and SBPFv3 migration
- Solana JavaScript SDK v3
Found an error or an outdated detail? Send a correction.
