Web3 Javascript Events & Logs API

在Blockchain世界里,每一笔交易(transaction)都必须等待矿工将资料写入block后,交易才能算真正完成。Ethereum提供了Evernts&Logs机制,让使用者或者其他contract可以藉由追踪Events&Logs来确认事件是否完成。可是说Events&Logs是contract之间或contract与Dapp的一道桥梁。当我们跟contract互动发生的事件称之为Event,而contract将事件写入到日志中称之为Log,日志一样会被纪录在block之中来供人查阅。

block除了纪录contract状态之外也会纪录Logs

Event&Logs用途

Events&Logs主要的用途有以下三种:

Receive data for transaction

当对contract的function发起sendTransaction呼叫时,会回传transaction hash。必须等到矿工把这次的transaction写入block中,contract的状态才会改变,呼叫contract的动作才算真正完成。我们可以利用event的机制来帮助我们得知什么时候contract的状态改变并获得改变后的值。

Asynchronous Notifications

利用Events&Logs机制,可以用来监听contract的状态,并且可以根据特定的情形触发特定的操作。例如当收到买家转来的款项,通知卖家把货寄出。

卖家可以利用追踪event的方式判断顾客是否付款

Cheap data for transaction

EventS&Logs可以拿来当作比较便宜的储存空间,像是存放加密的客户身份(Encrypted customer identity)。因为储存log data每一byte只需要花费8 gas。contract data则每一byte需要625 gas(20000 Gas/32-byte)。资料存放log中相较contract算是比较便宜。有一点要特别注意,虽然存放在log比较便宜,但contract却无法直接存取log中的资料。

Web3.js Events&Log API

在Web3.js主要有两种途径可以获得contract log,分别是Filter Instance和Contract Event Instance。这两种途径都分别提供的get()和watch()的功能。使用下方contract event来介绍实际该怎么使用Web3.js Events&Logs API

event NumberSetEvent(address indexed caller, bytes32 indexed oldNum, bytes32 indexed newNum)

当有人去修改contract变数值时,NumberSetEvent会将修改人的帐户地址(address)和原本contract变数值(oldNum)跟要修改的值(newNum)纪录到Log中。

Filter Instance Get/Watch Log

在建立Filter Instance之前我们必须要先设定一些参数。建立一个JSOM object里面存放Log的相关讯息。

topics是一个Array,其中第一个值是event的signature,是将event hash过后所得的值。存放在block中纪录的就是event hash。第二、三和四个值分别对应event的第一(address)、二(oldNum)和三(newNum)参数。这边可以指定要取得特定值的log,例如对应newNum第四个值写成

0x0000000000000000000000000000000000000000000000000000000000000005

代表只拿newNum等于5的log。null代表不指定。

function getOptionObject(){ 
    var options = { 
        "fromBlock": "0", // from block 
        "toBlock": "latest", // to block 
        "address": address, // contract address 
        "topics": [ 
            web3. sha3(NumberSetEvent('address,bytes32,bytes32)'), 
            null, // specific caller value 
            null, // specific oldNum 
            null // specific newNum 
        ] 
    }; 
    return options; 
}

使用web3.eth.filter来生成filter instance,参数就是刚刚建好的JSON object(options)。使用filter instance get()就可以在callback function拿到回传的log。以我们范例还来说就是拿从第一个到最后一个block中所有的log。回传会是一个array。

/* Get contract log data from filter instance*/ 
function getFilterEvents(){ 
    var options = getOptionObject(); 
    var filterGet = web3.eth.filter(options); 
    filterGet.get(function(error, result){ 
        if(error) { 
            // error handle 
        } else { 
            for(var i = 0; i < result.length ; i++){ 
                // print every log data 
                console.log(result[i]); 
            } 
        } 
    }); 
}

Watch顾名思义就是监控,当我们使用filter instance的watch()便会开始监控contract event,一旦有变动便会呼叫callback function执行对应的动作。若想要停止监控只要呼叫stopWatching()即可。

/* Watch contract log by filter instance */ 
function startWatchFilterEvents(){ 
    var options = getOptionObject(); 
    filterWatch = web3.eth.filter(options); 
    filterWatch.watch(function(error, result){ 
        if(error){ 
            / / error handle 
        } else { 
            // print watch log 
            console.log(result); 
        } 
    }); 
}/* Stop watch contract log /* 
filterWatch.stopWatching();

Contract Event Instance Get/Watch Log

除了Web3的Filter Instance之外我们还可以利用Web3 Contract Event Instance来取得log。先利用contract abi和contract address来建立contract instance。需要建立contract event instance必须提供两个参数,分别是:

当indexedEventValues和additionFilterOptions都准备好,就可以利用contract instance来建立contract event instance。方式如下:

contractInstance.EVENT_NAME( 
    indexedEventValues, additionalFilterOptions);

EVENT_NAME就是event的名字,以范例来说就是NumberSetEvent。

function createContractEventInstance(){ 
    var contract = web3.eth.contract(abi); 
    var contractInstance = contract.at(address); 
    var additionalFilterOptions = { 
        "fromBlock": "0", 
        "toBlock": "latest" 
    };    var indexedEventValues = { 
        "newNum": "0x0000000000000000000000000000000000000000000000000000000000000005" 
    };    // contractInstance.EVENT_NAME, NumberSetEvent is EVENT_NAME 
    return contractInstance.NumberSetEvent( 
               indexedEventValues, additionalFilterOptions); 
}

生成contract event instance后,就可以使用get()和watch()来获取log资讯。使用方法基本上跟Filter Instance获取log方式相同。

/* Get contract log from contract event instance */ 
function getContractEvents() { 
    var event = createContractEventInstance(); 
    event.get(function(error, result){ 
        if(error){ 
            console.log("Get event error:", error); 
        } else { 
            for(var i = 0; i < result.length ; i++){ 
                console.log(result[i]); 
            } 
        } 
    }); 
}
/* Watch contract log by contract event instance */ 
function startWatchContractEvents() { 
    var contractEvent = createContractEventInstance(); 
    contractEvent.watch(function(error, result){ 
        if(error){ 
            console.log("Get event error:", error); 
        } else { 
            console.log(result); 
        } 
    }); 
}/* Stop watching */ 
contractEvent.stopWatching()

结尾

这边谈论到Ethereum Events&Logs机制。主要聚焦在Event&Logs是什么东西和Web3.js该如何去使用它。因为还没有学习到smart contract的编写,所以有些东西打算保留到那时再提。到这里算是把个人觉得Web3.js一些比较常见的基础操作都稍微介绍过一遍。以上若有发现错误的地方,或者我的观念有误,拜托各位大大不吝啬给于纠正。

本文链接地址:https://www.wwsww.cn/btbjiaoxue/6248.html
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

标签:

相关文章阅读

熊市生存指南熊市生存指南
web3.eth.compile.solidity()替代方案web3.eth.compile.solidity()替代方案
Web3 Javascript API及常用操作Web3 Javascript API及常用操作