如何讀取智能合約存儲區(qū)塊鏈
智能合約是區(qū)塊鏈技術(shù)的重要應用,所有部署在EVM上的合約都有專門用于存放狀態(tài)的存儲,本次區(qū)塊鏈安全團隊BUGX.IO給大家分享這個讀取思路。
一、前言
所有部署在EVM上的合約都有專門用于存放狀態(tài)(state)的存儲(storage)。這里是一個示例如何使用web3 js庫 `eth.getStorageAt()`方法讀取這個存儲。
二、示例代碼
示例合約代碼位于: ropsten. etherscan. io/ address/ 0xf1f5896ace3a78c347eb7eab503450bc93bd0c3b
三、具體分析
從上面的示例代碼里,我們可以看到有11個狀態(tài)變量,現(xiàn)在我們逐個查看存儲中的狀態(tài)。
執(zhí)行:
npm install web3@ 0.20. 1
node storage. js
// storage.js
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/0x88f9c0F375FDF741b1E218aC66f30408F5a55527")); // 你的錢包賬戶地址
let contractAddress = '0xf1f5896ace3a78c347eb7eab503450bc93bd0c3b';
let storage = '';
for (index = 0; index < 10; index ){
storage = web3.eth.getStorageAt(contractAddress, index)
console.log(`[${index}]` storage)
}
// result:
// [0] 0x000000000000000000000000000000000000000000000000000000000000000f
// [1] 0x00000000000000000000000059b92d9a0000000000000000000000000000429f
// [2] 0x0000000000000000000000000000000074657374310000000000000000000000
// [3] 0x7465737431323336000000000000000000000000000000000000000000000000
// [4] 0x6c65747320737472696e6720736f6d657468696e67000000000000000000002a
// [5] 0x0000000000000000000000000000000000000000000000000000000000000000
// [6] 0x0000000000000000000000000000000000000000000000000000000000000000
// [7] 0x0000000000000000000000000000000000000000000000000000000000000002
// [8] 0x0000000000000000000000000000000000000000000000000000000000000002
// [9] 0x0000000000000000000000000000000000000000000000000000000000000000
(1) Index 0?—?storeduint1
uint storeduint1 = 15;
解碼代碼如下:
bytecode = '0x000000000000000000000000000000000000000000000000000000000000000f';
console. log( 'DEC:' web3. toDecimal( bytecode));
// DEC: 15
(2)constuint
uint constant constuint = 16;
常值不存放在存儲中,僅在代碼中可用。
(3)index 1?—?investmentsLimit, investmentsDeadlineTimeStamp
在 Index 1 中合并了這兩個屬性以優(yōu)化存儲的使用。
uint128 investmentsLimit = 17055;
uint32 investmentsDeadlineTimeStamp = uint32( now);
解碼代碼如下:
bytecode = '0x00000000000000000000000059b92d9a';
console. log( 'DEC:' web3. toDecimal( bytecode));
bytecode = '0x0000000000000000000000000000429f';
console. log( 'DEC:' web3. toDecimal( bytecode));
// DEC: 1505308058 and 17055
(4) index 2?—?string1
bytes16 string1 = 'test1';
解碼代碼如下:
bytecode = '0x0000000000000000000000000000000074657374310000000000000000000000';
console. log( 'ASCII:' web3. toAscii( bytecode))
// ASCII: test1
(5)index 3?—?string2
bytes32 string2 = 'test1236';
解碼代碼如下:
bytecode = '0x7465737431323336000000000000000000000000000000000000000000000000';
console. log( 'ASCII:' web3. toAscii( bytecode));
// ASCII: test1236
(6) index 4 — string3
string string3 = 'lets string something';
解碼代碼如下:
bytecode = '0x6c65747320737472696e6720736f6d657468696e67000000000000000000002a';
console. log( 'ASCII:' web3. toAscii( bytecode));
// ASCII:lets string something*
字節(jié)碼最后的符號 2a (dec 42) 用于表示存儲的字符串長度。
(7)index 5?—?uints1
mapping 類型的聲明形式為: `mapping(_KeyType => _ValueType)`
示例中的代碼為:
uint[] uintarray;
address address1 = 0xbccc714d56bc0da0fd33d96d2a87b680dd6d0df6;
uints1[ address1] = 88;
mapping 類型有不同的索引形式,需要不同的讀取方式。本例中,KeyType為address,ValueType為uint,要讀取mapping值88,那你需要知道KeyType的值,即address1,否則是不可能讀取得到的。
解碼代碼如下:
index = '0000000000000000000000000000000000000000000000000000000000000005'
key = '00000000000000000000000xbccc714d56bc0da0fd33d96d2a87b680dd6d0df6'
let newKey = web3. sha3( key index, { "encoding" : "hex"})
console. log( web3. eth. getStorageAt( contractAddress, newKey))
console. log( 'DEC: ' web3. toDecimal( web3. eth. getStorageAt( contractAddress, newKey)))
// result:
// 0x0000000000000000000000000000000000000000000000000000000000000058
// DEC: 88
(8) index6?—?structs1
相關(guān)代碼:
struct DeviceData {
string deviceBrand;
string deviceYear;
string batteryWearLevel;
}
address address1 = 0xbccc714d56bc0da0fd33d96d2a87b680dd6d0df6;
var dev1 = DeviceData( 'deviceBrand', 'deviceYear', 'wearLevel');
structs1[ address1] = dev1;
另一種形式的mapping類型,通過增加newkey的方式去讀取里面的其它內(nèi)容。
需要先安裝bignumber模塊: `npm install --save bignumber.js`
(9)index 7— uintarray
uint[] uintarray;
uintarray. push( 8000);
uintarray. push( 9000);
解碼代碼如下:
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/0x88f9c0F375FDF741b1E218aC66f30408F5a55527")); // 你的錢包賬戶地址
let contractAddress = '0xf1f5896ace3a78c347eb7eab503450bc93bd0c3b';
var BigNumber = require('bignumber.js');
function increaseHexByOne(hex) {
let x = new BigNumber(hex)
let sum = x.plus(1)
let result = '0x' sum.toString(16)
return result
}
// 先讀取 item 數(shù)
index = "7"
console.log(web3.eth.getStorageAt(contractAddress, index))
// result:
// 0x0000000000000000000000000000000000000000000000000000000000000002
// This array has 2 items
// 將index轉(zhuǎn)為sha3散列,可以讀取數(shù)組的值
index = "0000000000000000000000000000000000000000000000000000000000000007"
let newKey = web3.sha3(index, {"encoding":"hex"})
console.log(web3.eth.getStorageAt(contractAddress, newKey))
console.log('DEC: ' web3.toDecimal(web3.eth.getStorageAt(contractAddress, newKey)))
// result:
// 0x0000000000000000000000000000000000000000000000000000000000001f40
// DEC: 8000
// 通過增加sha3散列值的形式讀取其它位置的值
newKey = increaseHexByOne(web3.sha3(index, {"encoding":"hex"}))
console.log(web3.eth.getStorageAt(contractAddress, newKey))
console.log('DEC: ' web3.toDecimal(web3.eth.getStorageAt(contractAddress, newKey)))
// result:
// 0x0000000000000000000000000000000000000000000000000000000000002328
// DEC: 9000
(10)index 8 — deviceDataArray
DeviceData[] deviceDataArray;
var dev1 = DeviceData( 'deviceBrand', 'deviceYear', 'wearLevel');
var dev2 = DeviceData( 'deviceBrand2', 'deviceYear2', 'wearLevel2');
deviceDataArray. push( dev1);
deviceDataArray. push( dev2);
解碼過程如下:
結(jié)果如下:
1.TMT觀察網(wǎng)遵循行業(yè)規(guī)范,任何轉(zhuǎn)載的稿件都會明確標注作者和來源;
2.TMT觀察網(wǎng)的原創(chuàng)文章,請轉(zhuǎn)載時務必注明文章作者和"來源:TMT觀察網(wǎng)",不尊重原創(chuàng)的行為TMT觀察網(wǎng)或?qū)⒆肪控熑危?br>
3.作者投稿可能會經(jīng)TMT觀察網(wǎng)編輯修改或補充。