2021-06-25 15:59

技术分析:Solana如何实现账户交易?



solana官方的solana-program-library中给出了很多实用的实例,本次我们将介绍其中一个调用交易实例的例子,链接的examples中可以找到对应的rust program例程,我们用自定义的ts写的client去调用即可。 

生成钱包地址并领取空投: 

在发起交易前需要创建两个账户,并在其中添加相应的代币:

  • 创建两个新钱包,并输出json文件
$ solana-keygen new --outfile xxx.json 
  • 空投x个SOL到钱包的公钥地址中
$ solana airdrop x pubkey
  • cd到transfer-lamports的目录下
$ cd .../transfer-lamports
  • 编译rust项目,获得json和so文件
$ cargo build-bpf

ts程序中实现调用和交易的关键步骤:

1.建立一个JSON RPC连接

  • 首先获得solana的配置信息并做解析,这一步的信息也可用CLI的solana config get得出查看
async function getConfig(): Promise<any> {
  // Path to Solana CLI config file
  const CONFIG_FILE_PATH = path.resolve(
    os.homedir(),
    '.config',
    'solana',
    'cli',
    'config.yml',
  );
  const configYml = await fs.readFile(CONFIG_FILE_PATH, {encoding: 'utf8'});
  return yaml.parse(configYml);
}
  • 接着取其中的rpc_url建立连接
const config = await getConfig();
rpcUrl = config.json_rpc_url
connection = new Connection(rpcUrl, 'confirmed');

2.设置payer交易费用支付者

  • 首先计算建立账号所需的费用
const {feeCalculator} = await connection.getRecentBlockhash();
// Calculate the cost to fund the greeter account
fees += await connection.getMinimumBalanceForRentExemption(SIZE);
// Calculate the cost of sending transactions
fees += feeCalculator.lamportsPerSignature * 100; // wag
  • 接着从配置文件中读取密钥对作为支付者
const config = await getConfig();
payerAccount = readAccountFromFile(config.keypair_path);
  • 如果账户中的lamports余额低于最小要求时,则需要请求空投,一般这会发生在命令行配置的密钥对中
const lamports = await connection.getBalance(payerAccount.publicKey);
  if (lamports < fees) {
    const sig = await connection.requestAirdrop(
      payerAccount.publicKey,
      fees - lamports,
    );
    await connection.confirmTransaction(sig);
  }

3.检查BPF项目是否部署

在第一步我们编译rust生成bpf文件后,并没有进行部署,这一步就是为了检查项目是否部署在链上,通过检查programId是否有关联账号来判断。

  • 首先读取项目密钥对的路径文件,并获得公钥即programId,这个文件在编译后生成,一般在target/deploy目录下的json文件中
const PROGRAM_KEYPAIR_PATH = ('.../src/transfer-lamports/target/deploy/spl_example_transfer_lamports-keypair.json');
const programAccount = await readAccountFromFile(PROGRAM_KEYPAIR_PATH);
programId = programAccount.publicKey;
  • 接着读取programId的账户信息,通过查看账户信息判断是否部署,如果账户是空的并且存在so文件路径,则需要进行program部署,如果不存在so文件,则需要先进行编译生成文件再进行部署。如果账户存在,但是programInfo.executable是false,则代表program已经部署但无法执行,需要进行检查修改
const programInfo = await connection.getAccountInfo(programId);
  if (programInfo === null) {
    if (fs.existsSync(PROGRAM_SO_PATH)) {
      throw new Error(
        'Program needs to be deployed with `solana program deploy dist/program/helloworld.so`',
      );
    } else {
      throw new Error('Program needs to be built and deployed');
    }
  }
  else if (!programInfo.executable) {
    throw new Error(`Program is not executable`);
  }

4.交易指令发起

在完成前面的步骤后,则可进行ts的交易指令发起编写

  • 首先设置两个新钱包的json文件路径,并获取付款账号的公钥,这里为TransferOne
const TRANSFER_ONE = ('.../transfer_one.json');
const TRANSFER_TWO = ('.../transfer_two.json');
TransferOne = await readAccountFromFile(TRANSFER_ONE);
  • 新建一笔交易,添加指令,指令为系统指令,修改TransferOne账号拥有者为新的programId,原拥有者是系统。
const transaction =  new Transaction().add(
SystemProgram.assign({accountPubkey: TransferOne.publicKey, programId}) ,);
  • 发送交易并确认,发送账号要包含费用支付账号,转账者账号。
await sendAndConfirmTransaction(
        connection,
        transaction,
        [payerAccount,TransferOne],  
    );
  • 新建一个交易指令,把转账者和接受者的AccountMeta,programId,空的data添加进去。
const instruction = new TransactionInstruction({
      keys: [{pubkey: TransferOne.publicKey, isSigner: false, isWritable: true},
        {pubkey: TransferTwo.publicKey, isSigner: false, isWritable: true}],
      programId,
      data: Buffer.alloc(0), 
    });
  • 发送交易并确认
await sendAndConfirmTransaction(
      connection,
      new Transaction().add(instruction),
      [payerAccount],
    );


以上便是ts中关键的一些实现步骤,不包括全部代码,接下来便是CLi的命令执行和日志查看 

程序部署执行操作

  • 设置环境为本地
solana config set --url localhost 
  • 打开一个新终端,启动测试验证节点
solana-test-validator 
  • 打开一个新终端,启动solana日志监听
solana logs 
  • 打开一个新终端,在已经编译生成bpf文件的基础上,部署程序到链上
solana program deploy .../src/transfer-lamports/target/deploy/spl_example_transfer_lamports.so 
  • 安装npm环境
npm install 
  • 启动程序
npm run start 
  • 在rust中添加交易前后打印账号信息的代码,留意lamports的余额变化
Program log: source_info AccountInfo { key: 9yYpfeaZj5BR7t7NNwtVGriTVdQRrh3onNjDRJ3Q3hxj owner: 7t8m9KKZb3bDE4ez3CKR7cMF7NVHXbo7cU6zFVGWpjKb is_signer: false is_writable: true executable: false rent_epoch: 0 lamports: 9999999970 data.len: 0  }
Program log: destination_info AccountInfo { key: 8LNqub4QPXyNZKaHJCzgYaRDDwaYBp91abDhGoFzjP4X owner: 11111111111111111111111111111111 is_signer: false is_writable: true executable: false rent_epoch: 0 lamports: 1000000030 data.len: 0  }
Program log: source_info AccountInfo { key: 9yYpfeaZj5BR7t7NNwtVGriTVdQRrh3onNjDRJ3Q3hxj owner: 7t8m9KKZb3bDE4ez3CKR7cMF7NVHXbo7cU6zFVGWpjKb is_signer: false is_writable: true executable: false rent_epoch: 0 lamports: 9999999965 data.len: 0  }
Program log: destination_info AccountInfo { key: 8LNqub4QPXyNZKaHJCzgYaRDDwaYBp91abDhGoFzjP4X owner: 11111111111111111111111111111111 is_signer: false is_writable: true executable: false rent_epoch: 0 lamports: 1000000035 data.len: 0  }

可以看到lamports的数量进行了转移,

转账成功!


本文链接:https://www.8btc.com/media/6653420
转载请注明文章出处

评论
登录 账号发表你的看法,还没有账号?立即免费 注册
下载
阅读
分享
评论
点赞
上一篇
下一篇