¿Cómo explicar la serialización de cadenas al invocar el método de contrato?

En Ropsten testnet he implementado un contrato como este:

// creation of contract object
var aContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"lastIdMessage","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"readYourLastMessage","outputs":[{"name":"message","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"idMessage","type":"uint256"}],"name":"readYourMessageById","outputs":[{"name":"message","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"idMessage","type":"uint256"}],"name":"readYourMessageMetadataById","outputs":[{"name":"_idMessage","type":"uint256"},{"name":"_idPrevious","type":"uint256"},{"name":"_timestamp","type":"uint256"},{"name":"_from","type":"address"},{"name":"_message","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"timestamp","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"messages","outputs":[{"name":"idMessage","type":"uint256"},{"name":"idPrevious","type":"uint256"},{"name":"timestamp","type":"uint256"},{"name":"from","type":"address"},{"name":"message","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"countMessage","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"whoAmI","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"message","type":"string"}],"name":"sendMessage","outputs":[],"payable":false,"type":"function"},{"payable":false,"type":"fallback"}]);

// initiate contract for an address
var sc = aContract.at('0x59dbff7e055b09f02d5508a7c42f09b4683b2934');

Este contrato tiene un método que estoy tratando de invocar, pero primero necesito entender cómo codificar correctamente el parámetro de cadena:

// invoke contract method sendMessage(address,string)
sc.sendMessage.sendTransaction("0xa7e3c7c227c72a60e5a2f9912448fb1c21078769", "Hi Juan, this is marketpay sending first blockchain ever message!", {from:"0xf28dafbfeb41bf32869c9d498da0d651d0206ed4", gas:1000000});
    "0xe1a5d54c5b2ed440d55405ab73516245e909a2e345c734438fc9878801365c56"
    https://testnet.etherscan.io/tx/0xe1a5d54c5b2ed440d55405ab73516245e909a2e345c734438fc9878801365c56

De acuerdo con esta transacción anterior, puedo explorar cómo se serializaron los datos de cadena:

// hex header
0x

// 8 chars for method hash
de6f24bb

// 64 chars for first parameter, an account address
000000000000000000000000a7e3c7c227c72a60e5a2f9912448fb1c21078769

// 320 chars for encoding a string
000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000414869204a75616e2c2074686973206973206d61726b65747061792073656e64696e6720666972737420626c6f636b636861696e2065766572206d6573736167652100000000000000000000000000000000000000000000000000000000000000

Bueno, la pregunta es cómo puedo pasar de esta cadena:

"Hi Juan, this is marketpay sending first blockchain ever message!"

a este valor hexadecimal? :

000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000414869204a75616e2c2074686973206973206d61726b65747061792073656e64696e6720666972737420626c6f636b636861696e2065766572206d6573736167652100000000000000000000000000000000000000000000000000000000000000

¿Dónde puedo encontrar un documento que explique la serialización de cadenas en Ethereum? ¡Gracias!

Respuestas (1)

Puede encontrar la documentación en Ethereum Contract ABI .

Desde la sección Uso de tipos dinámicos :

Para los tipos estáticos uint256 y bytes10, estos son directamente los valores que queremos pasar, mientras que para los tipos dinámicos uint32[] y bytes, usamos el desplazamiento en bytes hasta el inicio de su área de datos, medido desde el inicio del valor codificación (es decir, sin contar los primeros cuatro bytes que contienen el hash de la firma de la función).

Aquí está el desglose que he trabajado hasta ahora:

// Hex header
0x

// 8 chars for method hash
de6f24bb

// Address
000000000000000000000000a7e3c7c227c72a60e5a2f9912448fb1c21078769

// 0x40 = 64. This is the offset from the beginning of Address
// directly above to the start of the next set of hex strings
// ending with 41 directly below
0000000000000000000000000000000000000000000000000000000000000040

// 0x41 = 65. This is the length of the dynamic string
0000000000000000000000000000000000000000000000000000000000000041

// And this is the string contents. As it is 65 characters, it will
// take up 32 characters + 32 characters + 1 character
// web3.toUtf8("0x4869204a75616e2c2074686973206973206d61726b65747061792073656e6469")
// returns "Hi Juan, this is marketpay sendi"
4869204a75616e2c2074686973206973206d61726b65747061792073656e6469

// web3.toUtf8("6e6720666972737420626c6f636b636861696e2065766572206d657373616765")
// returns "ng first blockchain ever message"
6e6720666972737420626c6f636b636861696e2065766572206d657373616765

// web3.toUtf8("2100000000000000000000000000000000000000000000000000000000000000")
// returns "!"
2100000000000000000000000000000000000000000000000000000000000000

Ver también:

Según los documentos, la dirección es equivalente a uint160. ¿Tiene algo que ver con 0x40 = 64, el desplazamiento desde el comienzo de Dirección?
Sí. Es el desplazamiento desde el principio de Dirección para buscar en el segundo campo.