Novato aquí!
Todavía no estoy seguro de haber entendido cómo se almacenan físicamente algunas estructuras de Ethereum (asumiendo la implementación de Geth)
State Trie: solo una Merkle Patricia Tries fuera de la cadena almacenada usando LevelDB;
Storage Trie: una Merkle Patricia Trie por cuenta; almacenado fuera de la cadena junto con State Trie usando LevelDB;
Intentos de transacción: en realidad no se almacenan físicamente; una Merkle Patricia Trie se crea sobre la marcha cuando es necesario utilizando la lista de transacciones en bloque;
Recibos Trie: ni idea;
Bloques: los intentos de estado y almacenamiento se almacenan en archivos .ldb (LevelDB), pero ¿dónde puedo encontrar los archivos de bloque y en qué formato están almacenados?
El formato de la base de datos geth de bajo nivel es:
var databaseVerisionKey = new Buffer("DatabaseVersion"); // databaseVerisionKey tracks the current database version.
var headHeaderKey = new Buffer("LastHeader"); // headHeaderKey tracks the latest know header's hash.
var headBlockKey = new Buffer("LastBlock"); // headBlockKey tracks the latest know full block's hash.
var headFastBlockKey = new Buffer("LastFast"); // headFastBlockKey tracks the latest known incomplete block's hash duirng fast sync.
var fastTrieProgressKey = new Buffer("TrieSync"); // fastTrieProgressKey tracks the number of trie entries imported during fast sync.
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
var headerPrefix = new Buffer("h"); // headerPrefix + num (uint64 big endian) + hash -> header
var headerTDSuffix = new Buffer("t"); // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
var headerHashSuffix = new Buffer("n"); // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
var headerNumberPrefix = new Buffer("H"); // headerNumberPrefix + hash -> num (uint64 big endian)
var blockBodyPrefix = new Buffer("b"); // blockBodyPrefix + num (uint64 big endian) + hash -> block body
var blockReceiptsPrefix = new Buffer("r"); // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
var txLookupPrefix = new Buffer("l"); // txLookupPrefix + hash -> transaction/receipt lookup metadata
var bloomBitsPrefix = new Buffer("B"); // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
var preimagePrefix = new Buffer("secure-key-"); // preimagePrefix + hash -> preimage
var configPrefix = new Buffer("ethereum-config-"); // config prefix for the db
var BloomBitsIndexPrefix = new Buffer("iB"); // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress // Chain index prefixes (use `i` + single byte to avoid mixing data types).
Para obtener datos, debe construir recursivamente árboles a partir de estos datos. Al conocer el hash de la raíz del estado, puede encontrar la raíz del estado, y luego conoce los hashes de los hijos de la raíz del estado, por lo que conoce a los hijos para que pueda llegar a las hojas.
Dependiendo de la opción de geth --gcmode archive|fast|light
(también puede especificar cuántos bloques desea recordar), geth almacena o no algunos intentos.
Los diferentes intentos son el árbol de estado mundial (enlaces a cuentas), los intentos de almacenamiento (datos de cuenta) y los intentos de recibo (para recibos de transacciones).
Para obtener el valor "valor de muestra" del árbol (por ejemplo, la dirección del contrato). Debe recorrer 32 longitudes hacia abajo en el árbol dependiendo de la longitud de 32 caracteres sha3 ("valor de muestra").
Para comprender mejor qué datos se almacenan en db y cómo se realizan los intentos, mire estas imágenes:
Canonista juramentado
jabone
Canonista juramentado
jabone
Nulik
hash
siendo elkey
y la estructura de datos correspondiente siendo elvalue
. Eso es todo. ¿Por qué necesitaría profundizar en la estructura de la base de datos, simplemente use las funciones que ethereum tiene para obtener los datos que necesita?