MSP Serverless平台链上交互框架 #
框架方案 #
架构 #
MSP Serverless编程框架支持用户自定义provider,应用程序编译成的wasm也就是actor可以通过abi,以类似于本地函数调用的方式与provider进行交互。在本例中,我们实现了weelink的provider,使得wasm程序可以非常方便的与区块链进行交互。

abi接口 #
定义weelink交互的abi接口,可以执行/查询任意的链上合约。abi具体定义如下:
invoke(method, args string)
发送交易接口,调用的链码函数名称以及对应的参数数组json marshal后的字符串
query(method, …args string)
发送交易接口,查询的链码函数名称以及对应的参数数组json marshal后的字符串
interface #
使用smithy定义上述abi,定义Invoke 和 Query的operation。然后使用wash工具生成rust的SDK库,这样provider和actor可以利用这个库来极大的简化代码。
/// The Weelink service has a single method, calculate, which
/// calculates the factorial of its whole number parameter.
@wasmbus(
contractId: "wasmcloud:oneitfarm:weelink",
actorReceive: true,
providerReceive: true )
service Weelink {
version: "0.1",
operations: [ Invoke, Query ]
}
/// Invoke - Execute transaction
operation Invoke {
input: InvokeRequest,
output: InvokeResponse,
}
/// Query - Get info from contract.
operation Query {
input: QueryRequest,
output: QueryResponse,
}
provider #
对于provider,实现invoke和query的方法,向链上进行数据交互。其主要逻辑如下所示:
/// Handle Weelink methods
#[async_trait]
impl Weelink for FakePayProvider {
async fn invoke(&self, ctx: &Context, arg: &InvokeRequest) -> RpcResult<InvokeResponse>{
// ...
let res = dyncallgo::call_invoke(method_ref, addr_ref, amount);
match res {
Ok(message) => Ok(InvokeResponse{success: true, message: Some(message.to_string()) }),
Err(e) => Ok(InvokeResponse{success: false, message: Some(format!("{:?}", e)) }),
}
}
/// Query - Get info from contract.
async fn query(&self, ctx: &Context, arg: &QueryRequest) -> RpcResult<QueryResponse>{
// ...
let res = dyncallgo::call_query(method_ref, addr_ref);
match res {
Ok(message) => Ok(QueryResponse{success: true, message: Some(message.to_string()) }),
Err(e) => Ok(QueryResponse{success: false, message: Some(format!("{:?}", e)) }),
}
}
}
actor #
actor可以实现任意的业务逻辑,这里我们实现一个测试的actor,当actor的invoke接口被调用时,actor就调用provider进行token transfer。当actor的query接口被调用时,actor查询参数指定的address的token余额。
其核心逻辑如下,判断接口是否是invoke,然后执行对应的逻辑:
/// Implementation of HttpServer trait methods
#[async_trait]
impl HttpServer for WeelinkActor {
/// Returns a greeting, "Hello World", in the response body.
/// If the request contains a query parameter 'name=NAME', the
/// response is changed to "Hello NAME"
async fn handle_request(
&self,
_ctx: &Context,
req: &HttpRequest,
) -> std::result::Result<HttpResponse, RpcError> {
info!("request arrived");
let provider = WeelinkSender::new();
if req.path.contains("invoke") {
let invoke_request = &InvokeRequest{address, amount:count, method:"".to_string()};
let res = provider.invoke(_ctx, invoke_request).await?;
if !res.success {
/* handle not authorized */
return Result::Err(RpcError::from(format!("invoke failed {}", res.message.unwrap()).to_string()));
}
message = res.message.unwrap().clone(); // todo change unwrap to match
} else {
let res = provider.query(_ctx, query_request).await?;
if !res.success {
/* handle not authorized */
return Result::Err(RpcError::from(format!("query failed {}", res.message.unwrap()).to_string()));
}
message = res.message.unwrap().clone(); // todo change unwrap to match
}
Ok(HttpResponse {
body: message.as_bytes().to_vec(),
..Default::default()
})
}
}
模型试验 #
步骤 #
添加provider

添加actor

定义link


效果 #
对wasm代码进行调用,首先调用账户查看函数,然后调用账户交易函数,再次调用账户查看函数显示账户余额。

wasmcloud弹性平台界面

意义 #
本模型试验表明wasm代码可以借助provider与链上交互的功能,通过调用本地ABI函数的方式,获取与链上进行信息交互的能力,同时wasm作为一种程序,可以在其中实现任意的业务逻辑,作为打通链上链下交互的serverless桥梁。
基础知识 #
合约 #
weelink支持以太坊智能合约,因此本次测试采用标准ERC20合约进行模型试验。
rust调用go动态链接库 #
与链上交互流程由go语言实现,编程成动态链接库供rust使用。go源码目前在/Users/zc/Desktop/companyWorkspace/blockchain/chain_adapter/codetest/web3/eth/wasmclouddemo当中。
备注 #
由于go provider将在近期支持,而且rust链上操作的流程和库开发工作量大,对当前公司内部技术栈来说,维护心智也高一点。因此采用rust调用go动态链接库方式实现初版demo,后续切换到go provider。以tinygo方式实现actor,降低程序编写门槛。