Web3js
如何從交易數據建構原始乙太坊交易
假設我有以下交易資訊:
{ "jsonrpc":"2.0" "id":0 "result":{ "blockHash":"0x43dd926aa138a58d3f4740dae387bcff3c7bc525db2d0a449f323f8b8f92a229" "blockNumber":"0xa4f285" "from":"0xea8a7ef30f894bce23b42314613458d13f9d43ea" "gas":"0x30d40" "gasPrice":"0x2e90edd000" "hash":"0x72ee43a3784cc6749f64fad1ecf0bbd51a54dd6892ae0573f211566809e0d511" "input":"0x" "nonce":"0x1e7" "to":"0xbd064928cdd4fd67fb99917c880e6560978d7ca1" "transactionIndex":"0x0" "value":"0xde0b6b3a7640000" "v":"0x25" "r":"0x7e833413ead52b8c538001b12ab5a85bac88db0b34b61251bb0fc81573ca093f" "s":"0x49634f1e439e3760265888434a2f9782928362412030db1429458ddc9dcee995" } }
除了您可能需要的有關網路的任何其他內容(例如
chain_id
)。是否可以在不知道發件人私鑰的情況下從這些資訊構造一個類似的原始交易?
隨意使用您最喜歡的 Web3 SDK。
原始交易只是以RLP格式編碼的所有交易參數。原始交易包括(按此順序):
- 隨機數;
- 天然氣價格;
- 氣體限制;
- 講話;
- 價值;
- 數據。
您不需要發送者的私鑰:要獲取原始交易,您可以簡單地使用
RLP(Nonce, Gas Price, Gas limit, To, Value, Data)
. 這是 JavaScript 中的範例實現(使用ethereumjs/rlp):import { encode } from 'rlp'; const transaction = { nonce: '0x1e7', gasPrice: '0x2e90edd000', gasLimit: '0x30d40', to: '0xbd064928cdd4fd67fb99917c880e6560978d7ca1', value: '0xde0b6b3a7640000', data: '0x' }; // Raw transaction as Buffer const rawTransaction = encode([transaction.nonce, transaction.gasPrice, transaction.gasLimit, transaction.to, transaction.value, transaction.data]); console.log(rawTransaction.toString('hex'));
這將導致以下原始事務:
ec8201e7852e90edd00083030d4094bd064928cdd4fd67fb99917c880e6560978d7ca1880de0b6b3a764000080
唯一需要私鑰的部分是簽署交易。簽名交易基本上是原始交易,添加了
v
,r
和s
簽名(原始交易):RLP(Nonce, Gas Price, Gas limit, To, Value, Data, v, r, s)
. 鏈 ID 編碼在v
參數中(參見EIP-155)。以下是如何簽署交易並獲取已簽署交易的範例:
import { randomBytes } from 'crypto'; import { ecsign, keccak256 } from 'ethereumjs-util'; import { encode } from 'rlp'; // Randomly generated 32 byte private key const privateKey = randomBytes(32); const transaction = { nonce: '0x1e7', gasPrice: '0x2e90edd000', gasLimit: '0x30d40', to: '0xbd064928cdd4fd67fb99917c880e6560978d7ca1', value: '0xde0b6b3a7640000', data: '0x', chainId: 1 }; const params = [transaction.nonce, transaction.gasPrice, transaction.gasLimit, transaction.to, transaction.value, transaction.data]; // Raw transaction as Buffer const rawTransaction = encode(params); const hash = keccak256(rawTransaction); // Signature of the hash of the raw transaction const { v, r, s } = ecsign(hash, privateKey, transaction.chainId); // RLP encoded signed transaction as Buffer const signedTransaction = encode([...params, v, r, s]); console.log(signedTransaction.toString('hex'));
請注意 的額外
chainId
屬性transaction
,這是獲取 的正確值所必需的v
。如果我們假設我們的簽名是範例交易中提到的簽名,則簽名交易如下所示:f86f8201e7852e90edd00083030d4094bd064928cdd4fd67fb99917c880e6560978d7ca1880de0b6b3a76400008025a07e833413ead52b8c538001b12ab5a85bac88db0b34b61251bb0fc81573ca093fa049634f1e439e3760265888434a2f9782928362412030db1429458ddc9dcee995
這是可以廣播到網路的完整交易。例如,您可以通過MyCrypto 的廣播工具來驗證這一點。