Reach 主题专栏系列文章围绕单主题解说并举例,本篇文章主题为 API。
本文由 Reach Developer Evangelist Hamza 编写,Ivan 翻译 原文链接
Reach 后端中的 API 是没有绑定到任何参与者的一组函数。也就是说,不同于参与者交互接口只能和特定参与者交互,API可以被任何人调用。
我们可以如下声明一个 API : API(name, interface) => API_Participant
例如: const Spectator = API('Spectator', { rate: Fun([UInt], Bool) })
API 接口中的每一个函数的定义域由 API 传入,并从合约得到回传值。在上面的例子里,调用Spectator.rate
时,API 会向合约发送一个 UInt ,并得到一个 Bool 回传值。
我们有两种方式可以调用 API 函数:
call()
函数fork
函数中的 .api()
函数call()
call( apiFn )
函数可以让 Reach 程序知道我们需要等待一个 API 函数调用。这个函数中包含了一个函数句柄(handle)
例如: const [[inputFromAPI], setReturnValue] = call(Spectator.rate)
一个 call
的回传值是一个元组,其中:
在上面的例子里,如果调用Spectator.rate()
时传入的值是 5
,最终得到的元组就是 [[5], setterFunction]
。
而 setterFunction(true)
会回传 true
给 API。
就步骤而言, call
相当于一个发布(publish),他可以与以下语法一起使用:
pay((<domain>) => <payment_amount>)
让 API 支付 <payment_amount>
const [[rating], setResponse] = call(Spectator.rate)
.pay((rating) => rating)
assume((<domain>) => <condition>)
确保诚实的参予者总保证 <condition>
为 true
.const [[rating], setResponse] = call(Spectator.rate)
.assume((rating) => rating < 10)
throwTimeout(<time>, <throw_expression>)
会报错 <throw_expression>
如果函数在 <time>
之内没有被调用。try {
const [[rating], setResponse] = call(Spectator.rate)
.throwTimeout(1024, 0)
}
catch (e) { ... }
下面是一个使用 call
的实例:
// Alice is implemented before
Alice.only(() => { doFlip() });
Alice.publish();
commit();
const [[rating], setResponse] = call(Spectator.rate)
.assume((rating) => rating < 10);
Alice.interact.seeRating(rating);
setResponse(true);
commit();
.api()
.api()
可以加入任何 fork 或 parallelReduce 语句中,作为一个由 API call 发起的 case。语法如下:
fork() // or parallelReduce(INIT_EXPR)
...
.api(API_EXPR,
API_ASSUME_EXPR,
API_PAY_EXPR,
API_CONSENSUS_EXPR)
其中
API_EXPR
是 API 参与者函数,API_ASSUME_EXPR
是一个以API传入值为传入值的函数,并回传一个bool 值,在参与者诚实时回传 true
值。这是一个可选的部份。API_PAY_EXPR
是一个以函数传入值为传入值的函数,并回传一个支付数额(pay amount),调用者会支付这个数额。这也是一个可选的部份。API_CONSENSUS_EXPR
是一个以函数传入值和设置函数为传入值的函数,随后发起共识转移。一个实例如下:
// PRICE_PER_RATING declared somewhere before
const totalScore = parallelReduce( 0 )
...
api(
Spectator.rate,
((rating) => { assume(rating < 10) }),
((rating) => rating * PRICE_PER_RATING)
((rating, setResponse) => {
setResponse(true);
return totalScore + rating;
})
);
API 函数储存在 contract.apis
或 contracts.a
中,其中每个API参与者都被存储为一个字段。
contracts.apis.Spectator
会回传 { rate: <async_function> }
...
const stdlib = loadStdlib(process.env);
const startingBalance = stdlib.parseCurrency(100);
const [deployer] = await stdlib.newTestAccount(startingBalance);
const contract = deployer.contract(backend);
try {
const res = await contract.apis.Spectator.rate(5);
}
catch (e) {
console.error("Error while calling Spectator.rate");
}
...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!