Cómo leer el almacenamiento por contrato de Ethereum

Todos hablan de que los datos en los contratos son públicos, pero no todos saben cómo leerlos.

Todos los contratos implementados en ethereum VM tienen almacenamiento dedicado donde se almacenan los estados. Aquí hay un ejemplo de cómo leer este almacenamiento con la biblioteca web3.js usando el método eth.getStorageAt ().

Ejemplo de contrato que examinamos:

Este contrato se implementa en la red de prueba Ropsten: en 0xf1f5896ace3a78c347eb7eab503450bc93bd0c3b

Todos los parámetros en el almacenamiento están indexados desde el principio. Un índice toma 256 bytes y se ajusta a 64 símbolos. En este ejemplo, tenemos 10 parámetros y podemos iterarlos:

let contractAddress = '0xf1f5896ace3a78c347eb7eab503450bc93bd0c3b'
para (índice = 0; índice <10; índice ++) {
 console.log (`[$ {index}]` +
   web3.eth.getStorageAt (contractAddress, index))
}
resultado:
[0] 0x000000000000000000000000000000000000000000000000000000000000000f
[1] 0x00000000000000000000000059b92d9a0000000000000000000000000000429f
[2] 0x0000000000000000000000000000000074657374310000000000000000000000
[3] 0x7465737431323336000000000000000000000000000000000000000000000000
[4] 0x6c65747320737472696e6720736f6d657468696e67000000000000000000002a
[5] 0x0000000000000000000000000000000000000000000000000000000000000000
[6] 0x0000000000000000000000000000000000000000000000000000000000000000
[7] 0x0000000000000000000000000000000000000000000000000000000000000002
[8] 0x0000000000000000000000000000000000000000000000000000000000000002
[9] 0x0000000000000000000000000000000000000000000000000000000000000000

Echemos un vistazo más profundo a cada parámetro

Índice 0 - storeduint1

let contractAddress = '0xf1f5896ace3a78c347eb7eab503450bc93bd0c3b'
dejar índice = 0
console.log (web3.eth.getStorageAt (contractAddress, index))
console.log ('DEC:' + web3.toDecimal (web3.eth.getStorageAt (contractAddress, index)))
resultado:
0x000000000000000000000000000000000000000000000000000000000000000f
DIC: 15

constuint

Las constantes no se almacenan en un almacenamiento. Disponible solo en código.

Índice 1 - inversiones Límite, inversionesDeadlineTimeStamp

let index = 1
console.log (web3.eth.getStorageAt (contractAddress, index))
resultado:
 0x00000000000000000000000059b92d9a0000000000000000000000000000429f
DIC: 1505308058 y 17055

En el índice 1 se fusionan 2 propiedades para optimizar el uso del almacenamiento.

índice 2 - cadena1

índice = 2
console.log (web3.eth.getStorageAt (contractAddress, index))
console.log ('ASCII:' +
 web3.toAscii (web3.eth.getStorageAt (contractAddress, index)))
resultado:
0x0000000000000000000000000000000074657374310000000000000000000000
ASCII: prueba1

índice 3 - cadena2

índice = 3
console.log (web3.eth.getStorageAt (contractAddress, index))
console.log ('ASCII:' +
 web3.toAscii (web3.eth.getStorageAt (contractAddress, index)))
resultado:
0x7465737431323336000000000000000000000000000000000000000000000000
ASCII: test1236

índice 4— cadena3

índice = 4
console.log (web3.eth.getStorageAt (contractAddress, index))
console.log ('ASCII:' +
 web3.toAscii (web3.eth.getStorageAt (contractAddress, index)))
resultado:
0x6c65747320737472696e6720736f6d657468696e67000000000000000000002a
ASCII: permite encadenar algo * (42)

El símbolo final 2a (dec 42) es la longitud de la cadena almacenada. (más detalles http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage)

índice 5 - uints1

índice = 5
console.log (web3.eth.getStorageAt (contractAddress, index))
resultado:
0x0000000000000000000000000000000000000000000000000000000000000000
¡¡¡¡PROBLEMA!!!!

Las asignaciones tienen una indexación diferente y deben leerse de otra manera. Para leer el valor de mapeo, debe conocer el valor clave. De lo contrario, el valor de mapeo de lectura es imposible.

index = '0000000000000000000000000000000000000000000000000000000000000005'
clave = '00000000000000000000000xbccc714d56bc0da0fd33d96d2a87b680dd6d0df6'
let newKey = web3.sha3 (clave + índice, {"codificación": "hexadecimal"})
console.log (web3.eth.getStorageAt (contractAddress, newKey))
console.log ('DEC:' + web3.toDecimal (web3.eth.getStorageAt (contractAddress, newKey)))
resultado:
0x0000000000000000000000000000000000000000000000000000000000000058
DIC: 88

index6 - structs1

index = "0000000000000000000000000000000000000000000000000000000000000006"
clave = "00000000000000000000000xbccc714d56bc0da0fd33d96d2a87b680dd6d0df6"
let newKey = web3.sha3 (clave + índice, {"codificación": "hexadecimal"})
console.log (web3.eth.getStorageAt (contractAddress, newKey))
console.log ('ASCII:' +
 web3.toAscii (web3.eth.getStorageAt (contractAddress, newKey)))
resultado:
0x6465766963654272616e64000000000000000000000000000000000000000016
ASCII: deviceBrand

Para leer el segundo valor de estructura, debe aumentar el valor de newKey en 1

función aumentarHexByOne (hexadecimal) {
 let x = new BigNumber (hex)
 let sum = x.add (1)
 let result = '0x' + sum.toString (16)
 resultado devuelto
}
index = "0000000000000000000000000000000000000000000000000000000000000006"
clave = "00000000000000000000000xbccc714d56bc0da0fd33d96d2a87b680dd6d0df6"
let newKey = raiseHexByOne (
  web3.sha3 (clave + índice, {"codificación": "hexadecimal"}))
console.log (web3.eth.getStorageAt (contractAddress, newKey))
console.log ('ASCII:' +
 web3.toAscii (web3.eth.getStorageAt (contractAddress, newKey)))
resultado:
0x6465766963655965617200000000000000000000000000000000000000000014
ASCII: dispositivo Año

Si desea un tercer valor de estructura, aumente newKey una vez más.

índice 7— uintarray

index = "7"
console.log (web3.eth.getStorageAt (contractAddress, index))
resultado:
  0x0000000000000000000000000000000000000000000000000000000000000002

Esta matriz tiene 2 artículos.

index = "0000000000000000000000000000000000000000000000000000000000000007"
let newKey = web3.sha3 (índice, {"codificación": "hexadecimal"})
console.log (web3.eth.getStorageAt (contractAddress, newKey))
console.log ('DEC:' +
  web3.toDecimal (web3.eth.getStorageAt (contractAddress, newKey)))
resultado:
0x0000000000000000000000000000000000000000000000000000000000001f40
DIC: 8000
newKey = raiseHexByOne (web3.sha3 (index, {"encoding": "hex"}))
console.log (web3.eth.getStorageAt (contractAddress, newKey))
console.log ('DEC:' +
  web3.toDecimal (web3.eth.getStorageAt (contractAddress, newKey)))
resultado:
0x0000000000000000000000000000000000000000000000000000000000002328
DIC: 9000

índice 8— deviceDataArray

index = "0000000000000000000000000000000000000000000000000000000000000008"
let newKey = web3.sha3 (índice, {"codificación": "hexadecimal"})
console.log (web3.eth.getStorageAt (contractAddress, newKey))
console.log ('ASCII:' +
 web3.toAscii (web3.eth.getStorageAt (contractAddress, newKey)))
resultado:
0x6465766963654272616e64000000000000000000000000000000000000000016
ASCII: deviceBrand
index = "0000000000000000000000000000000000000000000000000000000000000008"
let newKey = aumentoHexByOne (web3.sha3 (índice, {"codificación": "hexadecimal"}))
console.log (web3.eth.getStorageAt (contractAddress, newKey))
console.log ('ASCII:' +
web3.toAscii (web3.eth.getStorageAt (contractAddress, newKey)))
resultado:
0x6465766963655965617200000000000000000000000000000000000000000014
ASCII: dispositivo Año

Aumentar en 2 resultados:

0x776561724c6576656c0000000000000000000000000000000000000000000012

ASCII: wearLevel

Aumente en 3 ingrese al segundo elemento en el resultado de la matriz:

0x6465766963654272616e64320000000000000000000000000000000000000018

ASCII: deviceBrand2

Fuentes:
https://github.com/ethereum/solidity/issues/1550
https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat
https://ethereum.stackexchange.com/questions/13910/how-to-read-a-private-variable-from-a-contract
https://github.com/ethereum/web3.js/issues/445

Echa un vistazo a nuestro campo de pruebas: ¡Aigang!

Más sobre Aigang - http://bit.ly/AigangWebsite
Libro blanco de Aigang - http://bit.ly/2hwAtkt
Aigang en Telegram - http://bit.ly/AigangTelegram
Obtenga las últimas actualizaciones de Aigang - http://bit.ly/AigangUpdates