Skip to content

Commit

Permalink
pubkey: Add a simple program comparing two pubkeys
Browse files Browse the repository at this point in the history
#### Problem

It can be expensive to compare two pubkeys in an on-chain program, but
it hasn't been quantified.

#### Summary of changes

Add a Rust and Zig program to do that
  • Loading branch information
joncinque committed Nov 18, 2024
1 parent 1f32e5d commit a80c326
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 35 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
name: Run tests against Zig implementations
strategy:
matrix:
program: [helloworld, transfer-lamports, cpi, token]
program: [helloworld, transfer-lamports, cpi, pubkey, token]
fail-fast: false
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -53,7 +53,7 @@ jobs:
name: Run tests against Rust implementations
strategy:
matrix:
program: [helloworld, transfer-lamports, cpi, token]
program: [helloworld, transfer-lamports, cpi, pubkey, token]
fail-fast: false
runs-on: ubuntu-latest
steps:
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
"cpi",
"cpi/pinocchio",
"helloworld",
"pubkey",
"token",
"transfer-lamports",
"transfer-lamports/pinocchio"
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ Note: `create_program_address` consumes 1500 CUs, and `invoke` consumes 1000, so
we can subtract 2500 CUs from each program to see the actual cost of the program
logic.

### Pubkey

A program to compare two `Pubkey` instances. This operation is very common in
on-chain programs, but it can be expensive.

| Language | CU Usage |
| --- | --- |
| Rust | 14 |
| Zig | 15 |

### Token

A reduced instruction set from SPL-Token. Includes an entrypoint, instruction
Expand Down
22 changes: 22 additions & 0 deletions pubkey/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "solana-program-rosetta-pubkey"
version = "1.0.0"
edition = "2021"

[features]
test-sbf = []

[dependencies]
solana-program-entrypoint = "2.1.0"
solana-pubkey = "2.1.0"

[dev-dependencies]
solana-instruction = "2.1.0"
solana-program-test = "2.1.0"
solana-sdk = "2.1.0"

[lib]
crate-type = ["cdylib", "lib"]

[lints]
workspace = true
24 changes: 24 additions & 0 deletions pubkey/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! A program demonstrating a comparison of pubkeys
#![deny(missing_docs)]
#![allow(clippy::arithmetic_side_effects)]

use solana_pubkey::Pubkey;

/// Entrypoint for the program
#[no_mangle]
pub extern "C" fn entrypoint(input: *mut u8) -> u64 {
unsafe {
let key: &Pubkey = &*(input.add(16) as *const Pubkey);
let owner: &Pubkey = &*(input.add(16 + 32) as *const Pubkey);

if *key == *owner {
0
} else {
1
}
}
}
#[cfg(target_os = "solana")]
#[no_mangle]
fn custom_panic(_info: &core::panic::PanicInfo<'_>) {}
solana_program_entrypoint::custom_heap_default!();
39 changes: 39 additions & 0 deletions pubkey/tests/functional.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use {
solana_instruction::{AccountMeta, Instruction},
solana_program_test::*,
solana_pubkey::Pubkey,
solana_sdk::{account::Account, signature::Signer, transaction::Transaction},
};

const PROGRAM_ID: Pubkey = Pubkey::from_str_const("PubkeyComp111111111111111111111111111111111");
const TEST_KEY: Pubkey = Pubkey::from_str_const("PubkeyComp111111111111111111111111111111112");

#[tokio::test]
async fn correct_key() {
let mut program_test = ProgramTest::new(
option_env!("PROGRAM_NAME").unwrap_or("solana_program_rosetta_pubkey"),
PROGRAM_ID,
None,
);
program_test.add_account(
TEST_KEY,
Account {
lamports: 100_000,
data: vec![0],
owner: TEST_KEY,
..Account::default()
},
);
let (banks_client, payer, recent_blockhash) = program_test.start().await;

let mut transaction = Transaction::new_with_payer(
&[Instruction::new_with_bincode(
PROGRAM_ID,
&(),
vec![AccountMeta::new_readonly(TEST_KEY, false)],
)],
Some(&payer.pubkey()),
);
transaction.sign(&[&payer], recent_blockhash);
banks_client.process_transaction(transaction).await.unwrap();
}
15 changes: 15 additions & 0 deletions pubkey/zig/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const std = @import("std");
const solana = @import("solana-program-sdk");

pub fn build(b: *std.Build) !void {
const target = b.resolveTargetQuery(solana.sbf_target);
const optimize = .ReleaseFast;
const program = b.addSharedLibrary(.{
.name = "solana_program_rosetta_pubkey",
.root_source_file = b.path("main.zig"),
.target = target,
.optimize = optimize,
});
_ = solana.buildProgram(b, program, target, optimize);
b.installArtifact(program);
}
30 changes: 30 additions & 0 deletions pubkey/zig/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.{
.name = "solana-program-rosetta-pubkey-zig",
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.13.0",

// This field is optional.
// This is currently advisory only; Zig does not yet do anything
// with this value.
.minimum_zig_version = "0.13.0",

// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
.@"solana-program-sdk" = .{
.url = "https://github.com/joncinque/solana-program-sdk-zig/archive/refs/tags/v0.14.0.tar.gz",
.hash = "1220bdfa4ea1ab6330959ce4bc40feb5b39a7f98923a266a94b69e27fd20c3526786",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"main.zig",
"../../LICENSE",
"../../README.md",
},
}
12 changes: 12 additions & 0 deletions pubkey/zig/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const std = @import("std");
const PublicKey = @import("solana-program-sdk").PublicKey;

export fn entrypoint(input: [*]u8) u64 {
const id: *align(1) PublicKey = @ptrCast(input + 16);
const owner_id: *align(1) PublicKey = @ptrCast(input + 16 + 32);
if (id.equals(owner_id.*)) {
return 0;
} else {
return 1;
}
}
2 changes: 0 additions & 2 deletions transfer-lamports/src/entrypoint.rs

This file was deleted.

31 changes: 0 additions & 31 deletions transfer-lamports/src/processor.rs

This file was deleted.

0 comments on commit a80c326

Please sign in to comment.