Solana中的native program

1. 引言

Solana中的native program,类似于Fabric的系统合约,或以太坊的预编译合约。
每个validator节点会运行一小部分有用的native program。与第三方合约不同,native合约是作为validator的一部分进行运行的,且可随着cluster的升级而升级。

升级针对的场景有:

  • 增加feature
  • fix bugs
  • 改进性能
  • 个别指令的接口修改比较罕见。一般是增加新的指令,并将之前的指令标记为deprecated。

对于每个native program,会提供相应的program id和所支持instruction对应的description。
一笔交易中,可混合匹配不同native合约的指令,以及包含on-chain合约的指令。

Solana目前支持的native合约有:

  • System Program
  • Config Program
  • Stake Program
  • Vote Program
  • BPF Loader
  • Secp256k1 Program

2. System Program

System Program用于:

  • 创建新账号
  • 分配account data
  • assign accounts to owning programs
  • transfer lamports from System Program owned accounts and pay transaction fees。

对应的:

  • program id为:11111111111111111111111111111111
  • 指令有:
pub enum SystemInstruction {
    CreateAccount {
        lamports: u64,
        space: u64,
        owner: Pubkey,
    },
    Assign {
        owner: Pubkey,
    },
    Transfer {
        lamports: u64,
    },
    CreateAccountWithSeed {
        base: Pubkey,
        seed: String,
        lamports: u64,
        space: u64,
        owner: Pubkey,
    },
    AdvanceNonceAccount,
    WithdrawNonceAccount(u64),
    InitializeNonceAccount(Pubkey),
    AuthorizeNonceAccount(Pubkey),
    Allocate {
        space: u64,
    },
    AllocateWithSeed {
        base: Pubkey,
        seed: String,
        space: u64,
        owner: Pubkey,
    },
    AssignWithSeed {
        base: Pubkey,
        seed: String,
        owner: Pubkey,
    },
    TransferWithSeed {
        lamports: u64,
        from_seed: String,
        from_owner: Pubkey,
    },
}

3. Config Program

Config Program可用于:

  • add configuration data to the chain and the list of public keys that are permitted to modify it

Config Program对应的:

  • Program id为:Config1111111111111111111111111111111111111
  • 指令有:
    create_account:Create a new, empty configuration account
    store:Store new data in a configuration account。该指令的data为:a set of keys that gate access to the account 以及 the data to store in it。

4. Stake Program

Stake Program可用于:

  • create and manage accounts representing stake and rewards for delegations to validators。

Stake Program对应的:

  • Program id为:Stake11111111111111111111111111111111111111
  • 指令有:
pub enum StakeInstruction {
    Initialize(Authorized, Lockup),
    Authorize(Pubkey, StakeAuthorize),
    DelegateStake,
    Split(u64),
    Withdraw(u64),
    Deactivate,
    SetLockup(LockupArgs),
    Merge,
    AuthorizeWithSeed(AuthorizeWithSeedArgs),
    InitializeChecked,
    AuthorizeChecked(StakeAuthorize),
    AuthorizeCheckedWithSeed(AuthorizeCheckedWithSeedArgs),
    SetLockupChecked(LockupCheckedArgs),
}

5. Vote Program

Vote Program可用于:

  • create and manage accounts that track validator voting state and rewards

Vote Program对应的:

  • Program id为:Vote111111111111111111111111111111111111111
  • 指令有:
pub enum VoteInstruction {
    InitializeAccount(VoteInit),
    Authorize(Pubkey, VoteAuthorize),
    Vote(Vote),
    Withdraw(u64),
    UpdateValidatorIdentity,
    UpdateCommission(u8),
    VoteSwitch(Vote, Hash),
    AuthorizeChecked(VoteAuthorize),
}

6. BPF Loader

BPF Loader可用于:

  • deploy programs on the chain
  • upgrade programs on the chain
  • execute programs on the chain

BPF Loader对应的:

  • Program id为:BPFLoaderUpgradeab1e11111111111111111111111
  • 指令有:
#[repr(u8)]
pub enum UpgradeableLoaderInstruction {
    InitializeBuffer,
    Write {
        offset: u32,
        bytes: Vec<u8, Global>,
    },
    DeployWithMaxDataLen {
        max_data_len: usize,
    },
    Upgrade,
    SetAuthority,
    Close,
}

The BPF Upgradeable Loader marks itself as “owner” of the executable and program-data accounts it creates to store your program. When a user invokes an instruction via a program id, the Solana runtime will load both your the program and its owner, the BPF Upgradeable Loader. The runtime then passes your program to the BPF Upgradeable Loader to process the instruction.
详细的合约部署流程参见:
Solana Deploy a Program

7. Secp256k1 Program

Secp256k1 Program用于:

  • verify secp256k1 public key recovery operations (ecrecover)

Secp256k1 Program对应的:

  • Program id为:KeccakSecp256k11111111111111111111111111111
  • 指令有:
pub fn new_secp256k1_instruction(
    priv_key: &libsecp256k1::SecretKey,
    message_arr: &[u8],
) -> Instruction {
    let secp_pubkey = libsecp256k1::PublicKey::from_secret_key(priv_key);
    let eth_pubkey = construct_eth_pubkey(&secp_pubkey);
    let mut hasher = sha3::Keccak256::new();
    hasher.update(&message_arr);
    let message_hash = hasher.finalize();
    let mut message_hash_arr = [0u8; 32];
    message_hash_arr.copy_from_slice(message_hash.as_slice());
    let message = libsecp256k1::Message::parse(&message_hash_arr);
    let (signature, recovery_id) = libsecp256k1::sign(&message, priv_key);
    let signature_arr = signature.serialize();
    assert_eq!(signature_arr.len(), SIGNATURE_SERIALIZED_SIZE);

    let mut instruction_data = vec![];
    instruction_data.resize(
        DATA_START
            .saturating_add(eth_pubkey.len())
            .saturating_add(signature_arr.len())
            .saturating_add(message_arr.len())
            .saturating_add(1),
        0,
    );
    let eth_address_offset = DATA_START;
    instruction_data[eth_address_offset..eth_address_offset.saturating_add(eth_pubkey.len())]
        .copy_from_slice(&eth_pubkey);

    let signature_offset = DATA_START.saturating_add(eth_pubkey.len());
    instruction_data[signature_offset..signature_offset.saturating_add(signature_arr.len())]
        .copy_from_slice(&signature_arr);

    instruction_data[signature_offset.saturating_add(signature_arr.len())] =
        recovery_id.serialize();

    let message_data_offset = signature_offset
        .saturating_add(signature_arr.len())
        .saturating_add(1);
    instruction_data[message_data_offset..].copy_from_slice(message_arr);

    let num_signatures = 1;
    instruction_data[0] = num_signatures;
    let offsets = SecpSignatureOffsets {
        signature_offset: signature_offset as u16,
        signature_instruction_index: 0,
        eth_address_offset: eth_address_offset as u16,
        eth_address_instruction_index: 0,
        message_data_offset: message_data_offset as u16,
        message_data_size: message_arr.len() as u16,
        message_instruction_index: 0,
    };
    let writer = std::io::Cursor::new(&mut instruction_data[1..DATA_START]);
    bincode::serialize_into(writer, &offsets).unwrap();

    Instruction {
        program_id: solana_sdk::secp256k1_program::id(),
        accounts: vec![],
        data: instruction_data,
    }
}

Secp256k1 Program处理的指令内容格式为:

pub struct SecpSignatureOffsets {
    pub signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytes
    pub signature_instruction_index: u8,
    pub eth_address_offset: u16, // offset to eth_address of 20 bytes
    pub eth_address_instruction_index: u8,
    pub message_data_offset: u16, // offset to start of message data
    pub message_data_size: u16,   // size of message data
    pub message_instruction_index: u8,
}

相应的伪代码实现为:

process_instruction() {
  for i in 0..count {
      // i'th index values referenced:
      instructions = &transaction.message().instructions
      signature = instructions[secp_signature_instruction_index].data[secp_signature_offset..secp_signature_offset + 64]
      recovery_id = instructions[secp_signature_instruction_index].data[secp_signature_offset + 64]
      ref_eth_pubkey = instructions[secp_pubkey_instruction_index].data[secp_pubkey_offset..secp_pubkey_offset + 32]
      message_hash = keccak256(instructions[secp_message_instruction_index].data[secp_message_data_offset..secp_message_data_offset + secp_message_data_size])
      pubkey = ecrecover(signature, recovery_id, message_hash)
      eth_pubkey = keccak256(pubkey[1..])[12..]
      if eth_pubkey != ref_eth_pubkey {
          return Error
      }
  }
  return Success
}

这将允许用户在交易中指定任意的指令data,用于signature and message data。通过设置特殊的指令 sysvar,可receive data from the transaction itself。

Solana中交易的cost为:需验证的签名数量 乘以 验签cost。

注意:
以上操作可在(至少部分)deserialization之后进行,但是所有的inputs都来源于交易data本身,因此,相对会比较容易实现交易处理的并行执行和PoH verification的并行执行。

参考资料

[1] Solana的native program
[2] Solana system program的system instruction

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值