Proposal: log binary data for Solidity

The program_id is not needed on "Program return data: " because it
always preceeded by the program invoke message, so no need to repeat
the program id. Also rename this to "Program return: " since "data"
is redundant.
This commit is contained in:
Sean Young
2021-09-17 09:14:49 +01:00
parent 1fa8b6b966
commit d714cf659c
17 changed files with 432 additions and 10 deletions

View File

@ -2645,6 +2645,13 @@ dependencies = [
"solana-program 1.8.0",
]
[[package]]
name = "solana-bpf-rust-log-data"
version = "1.8.0"
dependencies = [
"solana-program 1.8.0",
]
[[package]]
name = "solana-bpf-rust-many-args"
version = "1.8.0"
@ -3111,6 +3118,7 @@ dependencies = [
name = "solana-program"
version = "1.8.0"
dependencies = [
"base64 0.13.0",
"bincode",
"bitflags",
"blake3 1.0.0",

View File

@ -52,6 +52,7 @@ members = [
"rust/deprecated_loader",
"rust/dup_accounts",
"rust/error_handling",
"rust/log_data",
"rust/external_spend",
"rust/finalize",
"rust/instruction_introspection",

View File

@ -67,6 +67,7 @@ fn main() {
"deprecated_loader",
"dup_accounts",
"error_handling",
"log_data",
"external_spend",
"finalize",
"instruction_introspection",

View File

@ -0,0 +1,28 @@
/**
* @brief Example C-based BPF program uses sol_log_data
*/
#include <solana_sdk.h>
static const uint8_t return_data[] = { 0x08, 0x01, 0x44 };
extern uint64_t entrypoint(const uint8_t *input) {
SolAccountInfo ka[1];
SolParameters params = (SolParameters) { .ka = ka };
SolBytes fields[2];
if (!sol_deserialize(input, &params, SOL_ARRAY_SIZE(ka))) {
return ERROR_INVALID_ARGUMENT;
}
// Generate two fields, split at the first 0 in the input
fields[0].addr = params.data;
fields[0].len = sol_strlen((char*)fields[0].addr);
fields[1].addr = fields[0].addr + fields[0].len + 1;
fields[1].len = params.data_len - fields[0].len - 1;
sol_set_return_data(return_data, sizeof(return_data));
sol_log_data(fields, 2);
return SUCCESS;
}

View File

@ -0,0 +1,23 @@
[package]
name = "solana-bpf-rust-log-data"
version = "1.8.0"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-bpf-rust-log-data"
edition = "2018"
[dependencies]
solana-program = { path = "../../../../sdk/program", version = "=1.8.0" }
[features]
default = ["program"]
program = []
[lib]
crate-type = ["lib", "cdylib"]
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -0,0 +1,24 @@
//! @brief Example Rust-based BPF program that uses sol_log_data syscall
#![cfg(feature = "program")]
use solana_program::{
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, log::sol_log_data,
program::set_return_data, pubkey::Pubkey,
};
entrypoint!(process_instruction);
#[allow(clippy::cognitive_complexity)]
fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let fields: Vec<&[u8]> = instruction_data.split(|e| *e == 0).collect();
set_return_data(&[0x08, 0x01, 0x44]);
sol_log_data(&fields);
Ok(())
}

View File

@ -52,8 +52,8 @@ use solana_transaction_status::{
TransactionStatusMeta, TransactionWithStatusMeta, UiTransactionEncoding,
};
use std::{
cell::RefCell, collections::HashMap, env, fs::File, io::Read, path::PathBuf, str::FromStr,
sync::Arc,
cell::RefCell, collections::HashMap, convert::TryInto, env, fs::File, io::Read, path::PathBuf,
str::FromStr, sync::Arc,
};
/// BPF program file extension
@ -740,6 +740,58 @@ fn test_program_bpf_error_handling() {
}
}
#[test]
#[cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
fn test_return_data_and_log_data_syscall() {
solana_logger::setup();
let mut programs = Vec::new();
#[cfg(feature = "bpf_c")]
{
programs.extend_from_slice(&[("log_data")]);
}
#[cfg(feature = "bpf_rust")]
{
programs.extend_from_slice(&[("solana_bpf_rust_log_data")]);
}
for program in programs.iter() {
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new_for_tests(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin(&name, id, entrypoint);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
bank.freeze();
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
let instruction =
Instruction::new_with_bytes(program_id, &[1, 2, 3, 0, 4, 5, 6], account_metas);
let blockhash = bank.last_blockhash();
let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
let transaction = Transaction::new(&[&mint_keypair], message, blockhash);
let result = bank.simulate_transaction(transaction.try_into().unwrap());
assert!(result.result.is_ok());
assert_eq!(result.logs[1], "Program data: AQID BAUG");
assert_eq!(
result.logs[3],
format!("Program return: {} CAFE", program_id)
);
}
}
#[test]
fn test_program_bpf_invoke_sanity() {
solana_logger::setup();
@ -1091,7 +1143,7 @@ fn test_program_bpf_invoke_sanity() {
result.unwrap_err(),
TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
);
}
}
}
#[cfg(feature = "bpf_rust")]