我有一个在http:\localhost:3000
上运行的react项目,它连接到在http:\localhost:7545
上运行的ganache。
我在ganache上部署了一个小型智能合约,它增加了一个计数器并发出一个事件,就像这样。。。
// SPDX-License-Identifier: MIT
pragma solidity >0.8.0;
contract Pong {
uint public pong_count;
function ping() public returns (uint){
pong_count++;
emit Pinged(this, pong_count);
return pong_count;
}
event Pinged(Pong indexed me, uint count);
function pong() public returns (uint){
pong_count++;
emit Ponged(this, pong_count);
return pong_count;
}
event Ponged(Pong indexed me, uint count);
}
我想听听我合同中的Pinged
和Ponged
事件。
由于这只是我正在做的其他事情的助手项目,我从ganache帐户嵌入私钥,并从中创建帐户…
var pk_account = w3.eth.accounts.privateKeyToAccount(pk);
然后在我的代码的其他地方,我创建了一个名为ponger
的Pong合约实例,并将其存储在我的react应用程序中的上下文对象上,然后像这样使用send
调用ping((合约方法。。。
ctx.ponger.methods
.ping()
.send({from:ctx.pk_account.address})
.then((result,err)=>{
if (err){
console.log("pong error: ", err);
}
else {
console.log("pong : ", result);
result.gas = 200000;
ctx.pk_account.signTransaction(result, sent);
}
});
这就像一个魅力,本地回调sent
被正确调用。
我将事件侦听器添加到我的ponger
实例中。。。
function ev_Pong(ev, err){
console.log("got pong event", ev);
}
function ev_Ping(ev, err){
console.log("got ping event", ev);
}
ctx.ponger.events.Pinged(ev_Ping);
ctx.ponger.events.Ponged(ev_Pong);
这就是乐趣的开始。我在ev_Ping
中收到的消息是…
got ping event Error: The current provider doesn't support subscriptions: HttpProvider
at subscription.js:176:1
所以,嗯,我需要使用websocket而不是HTTP,对吧?这意味着我只连接到ws:\localhost:7545
而不是http:\localhost:7545
。
(此外:如果我使用MetaMask为我提供web3,我不会有任何这些问题…(
然而,我收到了这样的CORS错误。。。
Access to XMLHttpRequest at 'ws://localhost:7545/' from origin 'http://localhost:3000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
所以我的问题是如何克服CORS错误?我不确定这是一个ganache问题还是一个老式的CORS问题,或者什么。
我还不想放弃事件侦听和解析事件日志——尽管我意识到可能还有很长的路要走。
我发现了问题所在,这是我的错。web3-websocket提供程序没有强制执行CORS,所以它可以在我的用例中使用。
我遇到的问题是,即使我更改了发送给web3的URI中的协议,我仍然要求使用HTTPProvider
而不是WebsocketProvider
。
为了达到这样的目的,我对getWeb3.js做了一些更改。。。
const getWeb3 = (url) => {
...
if (url){
if (url.substring(0,2) === 'ws'){
const provider = new Web3.providers.WebsocketProvider(url);
const web3 = new Web3(provider);
console.log("Using WS URL for web3: ", url);
resolve(web3);
}
else {
const provider = new Web3.providers.HttpProvider(url);
const web3 = new Web3(provider);
console.log("Using HTTP URL for web3: ", url);
resolve(web3);
}
}
...
}
这很好。
从好的方面来说,它让我更好地理解了CORS。我真的不喜欢禁用浏览器中的任何内容。