Как объяснить сериализацию строк при вызове метода контракта?

В тестовой сети Ropsten я развернул такой контракт:

// 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');

В этом контракте есть метод, который я пытаюсь вызвать, но сначала мне нужно понять, как правильно кодировать строковый параметр:

// 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

В соответствии с этой предыдущей транзакцией я могу исследовать, как были сериализованы строковые данные:

// 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

Ну, вопрос в том, как я могу перейти от этой строки:

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

к этому шестнадцатеричному значению? :

000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000414869204a75616e2c2074686973206973206d61726b65747061792073656e64696e6720666972737420626c6f636b636861696e2065766572206d6573736167652100000000000000000000000000000000000000000000000000000000000000

Где я могу найти документ, объясняющий сериализацию строк в Ethereum? Спасибо!

Ответы (1)

Вы можете найти документацию на Ethereum Contract ABI .

Из раздела « Использование динамических типов »:

Для статических типов uint256 и bytes10 это непосредственно значения, которые мы хотим передать, тогда как для динамических типов uint32[] и bytes мы используем смещение в байтах до начала их области данных, измеренное от начала значения кодирование (т.е. не считая первых четырех байтов, содержащих хэш сигнатуры функции).

Вот разбивка, которую я разработал до сих пор:

// 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

Смотрите также:

Согласно документам, адрес эквивалентен uint160. Это как-то связано с 0x40 = 64, смещением от начала адреса?
Ага. Это смещение от начала адреса для поиска во втором поле.