接下来就是开始下棋了。每下一步棋,就是对合约的一次调用,并触发合约状态的改变。Web 应用程序与合约的交互发生在这个阶段。
调用合约需要完成以下步骤:
通过当前实例的 .next()
方法创建一个新的合约实例。将新实例的状态更新到最新。
通过 bindTxBuilder
方法为 TicTacToe
合约的 move()
方法添加一个构建调用合约的交易 Builder
。
最后调用合约实例上的 methods
公共方法来发送交易以执行区块链上的合约。每个公共方法 xxx
在 instance.methods.xxx
下都有一个同名的函数。它采用相同的参数,外加一个 MethodCallOptions
参数。
如果公共方法的某个参数是 Sig
类型,则需要通过回调函数来返回签名。合约连接的 Signer
会使用默认私钥进行签名,并将签名结果通过回调函数的参数 sigResponses
返回。使用 findSig()
查找与一个公钥关联的签名。
通过 MethodCallOptions
中 pubKeyOrAddrToSign
可以指定 Signer
使用哪个公钥地址或公钥进行签名。
const { tx: callTx } = await p2pkh.methods.unlock( (sigResponses: SignatureResponse[]) => findSig(sigResponses, $publickey), $publickey, { pubKeyOrAddrToSign: $publickey } as MethodCallOptions<P2PKH> );
以上几个步骤的代码实现:
// 1. create nextInstance const current = props.contract as TicTacToe; const nextInstance = current.next(); // convert latest game data to contract state with Utils.toContractState and update nextInstance state Object.assign(nextInstance, Utils.toContractState(latestGameData)); // 2. bind a tx builder for move current.bindTxBuilder('move', async (current: TicTacToe, options: MethodCallOptions<TicTacToe>, n: bigint, sig: Sig) => { ... } // 3. call contract.methods.move(...) to broadcast transaction const {tx, nexts} = await current.methods.move( BigInt(i), (sigResponses: SignatureResponse[]) => findSig(sigResponses, $publickey), ); // 4. save latest contract instance props.setContract(nexts?.instance)
至此,我们就完成了TicTacToe合约与webapp的交互。玩家的每一次下棋动作都会在链上产生相应的交易。