RPC(Remote Procedure Calls )远程过程调用是一种协议,就是从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个函数或方法(可以统称为服务)并得到返回的结果。
RPC协议通常的实现有XML-RPC , JSON-RPC ,gRPC等,它们的通信方式基本相同, 所不同的只是传输数据的格式。
RPC是分布式架构的核心,按响应方式分如下两种:
一个完整的RPC架构里面包含了四个核心的组件,分别是Client,Client Stub,Server以及Server Stub:
RPC的调用流程如下图所示:
该流程中的具体步骤是:
RPC框架的目标,就是要上面步骤里2~10给封装好,让用户像调用本地服务一样的调用远程服务,实现对客户端(调用方)透明化服务。这个听起来好像不难,但真正落地实现,就要面对以下几个难题:
像以太坊等主流区块链实现的RPC,都是基于Json RPC的。目前的版本是V2.0。
下面就是一个请求对象的例子
{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}
下面是一个响应对象的例子:
{"jsonrpc": "2.0", "result": 19, "id": 1}
Solana也是基于JSON RPC来实现客户RPC调用的。
var solana_web3 = require('@solana/web3.js');
function testMemo(connection, account){
const instruction = new solana_web3.TransactionInstruction({
keys: [],
programId:new solana_web3.PublicKey('D8Cnv1UcThay2WijWP4SQ8G683UuVsKPaZEU7TNVKW1j'),
data: Buffer.from('cztest'),
});
console.log("account:", account.publicKey.toBase58())
solana_web3.sendAndConfirmTransaction(
connection,
new solana_web3.Transaction().add(instruction),
[account],
{
skipPreflight: true,
commitment: "singleGossip",
},
).then(()=>{console.log("done")}).catch((e)=>{console.log("error",e)});
}
function main() {
connection = new solana_web3.Connection("https://devnet.solana.com", 'singleGossip');
const account = new solana_web3.Account()
const lamports = 10*1000000000
connection.requestAirdrop(account.publicKey, lamports).then(()=>{
console.log("airdrop done")
testMemo(connection, account)
});
}
main()
其中commitment可选的值,有以下几种:
export type Commitment =
| 'processed'
| 'confirmed'
| 'finalized'
| 'recent'
| 'single'
| 'singleGossip'
| 'root'
| 'max';
注:我们基于C/C++ 来实现一个访问Solana合约的客户端,也可以参考该Web3.js的Dapp的处理逻辑与流程的。
除去去读取相应数据accounts,是否有类似Solidity合约的Event获取?该Event是否支持push模式,直接向客户端及时告知event的发生?
其实我们在前面 Solana JSON RPC API里已罗列了WebSocket的接口,这些接口,是实现了实时event的监听接口的。
所以我们只要按照标准的WebSocket连接,对关心的topic,进行sub,就可以获取到由Solana推过来的event的。具体的Javascript客户端通过WebSocket实时获取事件日志的步骤如下:
下载包
npm install --save express
npm install websocket
如果下载这监听的话:reconnecting 就会自带心跳机制不需从新加
(缺点只能TypeScript中使用)
npm install --save reconnecting-websocket
<html>
<head>
<!--加入下面这行代码避免出现中文乱码-->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="result"></div>
</body>
<script type="text/javascript">
//想要监听的地址
var socketUrl = `ws://api.devnet`;
var socket = new WebSocket(socketUrl);
//连接打开事件
//订阅日志事件logsSubscribe
//mentions这个参数相当于(交易号)
socket.onopen = function() {
console.log("Socket 已打开");
let rpc = {
jsonrpc: "2.0",
id: 1,
method: "logsSubscribe",
"params": [
{
"mentions": [ "Ef2FSTK4Jk7Yc3AiKoWhDrhdPdATTxPAngRRNSgDTdEY" ]
},
{
"commitment": "finalized"
}
]
//这个属于监听全部信息
//"params": [ "all" ]
}
socket.send(JSON.stringify(rpc));
};
//收到消息事件
socket.onmessage = function(msg) {
console.log("接受到消息:" + msg.data);
var result = document.getElementById("result").innerHTML;
result = result + "<br/>接收消息:" + msg.data;
document.getElementById("result").innerHTML = result;
};
//连接关闭事件
socket.onclose = function() {};
//发生了错误事件
socket.onerror = function() {
console.log("发生错误!");
}
</script>
</html>
这个例子,就是会去监听Solana上,是否有关于账户“Ef2FSTK4Jk7Yc3AiKoWhDrhdPdATTxPAngRRNSgDTdEY”的事情,或日志,有的话,它就会接收,并打印到Web的HTML页面中。
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
我想从then子句中访问case语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案
我理解(我认为)Ruby中类变量和类的实例变量之间的区别。我想知道如何从该类外部访问该类的实例变量。从内部(即在类方法中而不是实例方法中),它可以直接访问,但是从外部,有没有办法做MyClass.class.[@$#]variablename?我没有任何具体原因要这样做,只是学习Ruby并想知道是否可行。 最佳答案 classMyClass@my_class_instance_var="foo"class上述yield:>>foo我相信Arkku演示了如何从类外部访问类变量(@@),而不是类实例变量(@)。我从这篇文章中提取了上述内
我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token
我正在使用Ruby/Mechanize编写一个“自动填写表格”应用程序。它几乎可以工作。我可以使用精彩CharlesWeb代理以查看服务器和我的Firefox浏览器之间的交换。现在我想使用Charles查看服务器和我的应用程序之间的交换。Charles在端口8888上代理。假设服务器位于https://my.host.com。.一件不起作用的事情是:@agent||=Mechanize.newdo|agent|agent.set_proxy("my.host.com",8888)end这会导致Net::HTTP::Persistent::Error:...lib/net/http/pe
是否有可能以某种方式访问Class.new范围内的a?a=5Class.new{defb;aend}.new.b#NameError:undefinedlocalvariableormethod`a'for#:0x007fa8b15e9af0>#:in`b' 最佳答案 即使@MarekLipka的回答是正确的——改变变量范围总是有风险的。这是可行的,因为每个block都带有创建它的上下文,因此您的局部变量a突然变得不那么局部了——它变成了一个“隐藏的”全局变量:a=5object=Class.new{define_method(
使用散列定义的访问器方法动态创建对象的最简单方法是什么?例如,如果我有一个散列:{foo:"Foo",bar:"Bar"}我想要一个具有访问器方法foo、foo=、bar和bar=的对象,其初始值分别为"Foo"和"Bar"。我可以想到这样做:moduleObjectWithAccessordefself.newh;Struct.new(*h.keys).new(*h.values)endendo=ObjectWithAccessor.new(foo:"Foo",bar:"Bar")o.foo#=>"Foo"但是,我不需要它们的多个实例具有相同的特定键集,而是希望每次都使用可能不同的键
我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT