I am trying to find out if each transaction hash created by a wallet has some similarity or if every hash is "random".
I suppose my original question leads into whether or not a transaction hash be used to identify the wallet it came from?
hashidentitytransactionswallets
I am trying to find out if each transaction hash created by a wallet has some similarity or if every hash is "random".
I suppose my original question leads into whether or not a transaction hash be used to identify the wallet it came from?
There are some changes with the Byzantium fork - getTransactionReceipt(...).status
now returns 0 for a failed transaction and 1 for a successful transaction. EtherScan.io displays this status in the TxReceipt Status: field for transactions. See How do I detect a failed transaction after the Byzantium fork as the REVERT opcode does not consume all gas? for further information.
eth.getTransaction("{txhash}")
and eth.getTransactionReceipt("{txhash}")
will provide you with the details.
The .blockNumber
field will be null
until the transaction is included into a mined block.
The examples below show demonstrate some of the ways of detecting the status of a transaction.
Note that there could be an issue detecting whether a transaction has failed due to a thrown error, as the situation can be detected by checking whether gas = gasUsed
. I've created the question How can the transaction status from a thrown error be detected when gas can be exactly the same as the gasUsed for a successful transaction? to try to resolve this question.
And from the findings in the Q&A above, here's a short bit of code to determine the status of your transaction.
> var status = debug.traceTransaction("0x9ee86a200528de32a695f1e2dd0d94a3871fefc7e49c5fd24a4a37eab1b99f7a")
undefined
> status.structLogs[status.structLogs.length-1].error
"invalid jump destination (PUSH1) 2"
The return value above will be ""
if there are no errors, or "Out of gas"
if you run out of gas.
Following are some examples of using eth.getTransaction(...)
and eth.getTransactionReceipt(...)
to find out the transaction status.
Here's the output when there are no pending transactions
// eth.getBlock("pending").transactions[0] = null
> eth.getTransaction(eth.getBlock("pending").transactions[0])
invalid or missing value for params[0]
at web3.js:3119:20
at web3.js:6023:15
at web3.js:4995:36
at <anonymous>:1:1
And here's a pending transaction. .blockNumber = null
.
> eth.getTransaction(eth.getBlock("pending").transactions[0])
{
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
blockNumber: null,
from: "0xea674fdde714fd979de3edf0f56aa9716b898ec8",
gas: 90000,
gasPrice: 20000000000,
hash: "0xdfa60d4e97c242c5222a11b485c051bbdeb133c99baccd34dc33ceae1dc0cd67",
input: "0x",
nonce: 181930,
to: "0x4ac944f4e8ab60f9481bcecd78a9915ed3eb98ba",
transactionIndex: null,
value: 1005685497455181600
}
This transaction was executed successfully. gas(666666) < gasUsed(106824)
.
> eth.getTransaction(eth.getBlock("latest").transactions[1])
{
blockHash: "0x425a4d04ac0185863266b0d1b000f579f9675a37c5c6df3bf3cf72e0bc9a94e7",
blockNumber: 1701040,
from: "0x81747eb1afd9e2670aa6883ed80973ffcb531e1f",
gas: 666666,
gasPrice: 20000000000,
hash: "0x6ef5b459ed945fbabfc3a5ef34fb0087752002c319649ff44c3b2759d13a517d",
input: "0xf04fd2f3000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000001e0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
nonce: 16,
to: "0x2cac6e4b11d6b58f6d3c1c9d5fe8faa89f60e5a2",
transactionIndex: 1,
value: 0
}
> eth.getTransactionReceipt("0x6ef5b459ed945fbabfc3a5ef34fb0087752002c319649ff44c3b2759d13a517d")
{
blockHash: "0x425a4d04ac0185863266b0d1b000f579f9675a37c5c6df3bf3cf72e0bc9a94e7",
blockNumber: 1701040,
contractAddress: null,
cumulativeGasUsed: 127824,
from: "0x81747eb1afd9e2670aa6883ed80973ffcb531e1f",
gasUsed: 106824,
logs: [{
address: "0x2cac6e4b11d6b58f6d3c1c9d5fe8faa89f60e5a2",
blockHash: "0x425a4d04ac0185863266b0d1b000f579f9675a37c5c6df3bf3cf72e0bc9a94e7",
blockNumber: 1701040,
data: "0x00000000000000000000000081747eb1afd9e2670aa6883ed80973ffcb531e1f000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000010b000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000047e364",
logIndex: 0,
topics: ["0xa8061486280834731cc1ef340255cc5d9880ad748d20cb766f43cb7562ec2c16"],
transactionHash: "0x6ef5b459ed945fbabfc3a5ef34fb0087752002c319649ff44c3b2759d13a517d",
transactionIndex: 1
}, {
address: "0x2cac6e4b11d6b58f6d3c1c9d5fe8faa89f60e5a2",
blockHash: "0x425a4d04ac0185863266b0d1b000f579f9675a37c5c6df3bf3cf72e0bc9a94e7",
blockNumber: 1701040,
data: "0x000000000000000000000000c3a48462221f4525dd2823853b0d04cf373fe42e00000000000000000000000081747eb1afd9e2670aa6883ed80973ffcb531e1f000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000001c7000000000000000000000000000000000000000000000000000000000000010b000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000a03e8",
logIndex: 1,
topics: ["0x68a83b20dde5c87dee07cc8d46d46e2fda6f176227f8b1f20dcb93752557df0e"],
transactionHash: "0x6ef5b459ed945fbabfc3a5ef34fb0087752002c319649ff44c3b2759d13a517d",
transactionIndex: 1
}, {
address: "0x2cac6e4b11d6b58f6d3c1c9d5fe8faa89f60e5a2",
blockHash: "0x425a4d04ac0185863266b0d1b000f579f9675a37c5c6df3bf3cf72e0bc9a94e7",
blockNumber: 1701040,
data: "0x00000000000000000000000081747eb1afd9e2670aa6883ed80973ffcb531e1f000000000000000000000000c3a48462221f4525dd2823853b0d04cf373fe42e000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000001c7000000000000000000000000000000000000000000000000000000000000010b00000000000000000000000000000000000000000000000000000000000001840000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000272000000000000000000000000000000000000000000000000000000000047e558",
logIndex: 2,
topics: ["0x61a43b8785d66f3a53c7b8ab814b4c2e4ff15a1a6f8d24d08818e1f426e13906"],
transactionHash: "0x6ef5b459ed945fbabfc3a5ef34fb0087752002c319649ff44c3b2759d13a517d",
transactionIndex: 1
}, {
address: "0x2cac6e4b11d6b58f6d3c1c9d5fe8faa89f60e5a2",
blockHash: "0x425a4d04ac0185863266b0d1b000f579f9675a37c5c6df3bf3cf72e0bc9a94e7",
blockNumber: 1701040,
data: "0x00000000000000000000000000000000000000000000000000075fbf48b22000",
logIndex: 3,
topics: ["0x8f22ef5ca888de3e246c690a13b066ad49cbf2768b0449441dd6f5bae826a1b1"],
transactionHash: "0x6ef5b459ed945fbabfc3a5ef34fb0087752002c319649ff44c3b2759d13a517d",
transactionIndex: 1
}],
root: "30353b57e937cfc71f0c97d5c98573be1eff440e3db62987bd9cd66b0f3030c4",
to: "0x2cac6e4b11d6b58f6d3c1c9d5fe8faa89f60e5a2",
transactionHash: "0x6ef5b459ed945fbabfc3a5ef34fb0087752002c319649ff44c3b2759d13a517d",
transactionIndex: 1
}
Here is an example of a transaction that was successfully mined into the blockchain, but the contract execution failed.
In this case gas(50878) == gasUsed(50878)
.
This occurs because the Smart Contract code called by the transaction detected an error and threw an exception and this consumes ALL gas.
See Why does a Solidity throw consume all gas? for more information about the throwing of errors and gas usage.
And note that there could possibly be the case where a Smart Contract executes without any errors and consumes EXACTLY the same amount of gas as specified with the sent transaction details.
> eth.getTransaction("0x93f39d4213bc48d9e6adda181ddd468d18163ae894ffc3f1a81d34ea33629f84")
{
blockHash: "0x43403d50e782e2e4f0e9c94e43ce417b2adaf0e0f9fbb4147c2b288fe3c9dc75",
blockNumber: 1596065,
from: "0x46fbf1e97365513bb5bdb894259877e026b7f27d",
gas: 50878,
gasPrice: 32210000000,
hash: "0x93f39d4213bc48d9e6adda181ddd468d18163ae894ffc3f1a81d34ea33629f84",
input: "0x",
nonce: 2,
to: "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
transactionIndex: 0,
value: 211417498879620000000
}
> eth.getTransactionReceipt("0x93f39d4213bc48d9e6adda181ddd468d18163ae894ffc3f1a81d34ea33629f84")
{
blockHash: "0x43403d50e782e2e4f0e9c94e43ce417b2adaf0e0f9fbb4147c2b288fe3c9dc75",
blockNumber: 1596065,
contractAddress: null,
cumulativeGasUsed: 50878,
from: "0x46fbf1e97365513bb5bdb894259877e026b7f27d",
gasUsed: 50878,
logs: [],
root: "d6771cfbad8d1f2f7cf413a48e968654ec7626797d3ac0ee6cfac26bba09e352",
to: "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
transactionHash: "0x93f39d4213bc48d9e6adda181ddd468d18163ae894ffc3f1a81d34ea33629f84",
transactionIndex: 0
}
I'm sending more ethers than is available in my account. The error is caught before the transaction is mined into the blockchain.
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(50000000, "ether")})
Insufficient funds for gas * price + value
at web3.js:3119:20
at web3.js:6023:15
at web3.js:4995:36
at <anonymous>:1:1
I'm sending to an invalid address. Again the error is caught before the transaction is mined into the blockchain.
> eth.sendTransaction({from: eth.accounts[0], to: "0x12345", value: web3.toWei(50, "ether")})
invalid address
at web3.js:3887:15
at web3.js:3716:22
at web3.js:4939:28
at web3.js:4938:12
at web3.js:4964:18
at web3.js:4989:23
at <anonymous>:1:1
Here's an example where the gas(21000) == gasUsed(21000)
but the transaction went through successfully.
I made this up as the gas required for a regular transaction is 21000 and I specified the gas=21000
in the transaction details.
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1.2345, "ether"), gas: 21000})
"0xc7c63b67747c0c825229ce3d36d226423adb8cab6bebe12b6d5001e0dc3f79b3"
> eth.getTransaction("0xc7c63b67747c0c825229ce3d36d226423adb8cab6bebe12b6d5001e0dc3f79b3")
{
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
blockNumber: null,
from: "0xa7857047907d53a2e494d5f311b4b586dc6a96d2",
gas: 21000,
gasPrice: 20000000000,
hash: "0xc7c63b67747c0c825229ce3d36d226423adb8cab6bebe12b6d5001e0dc3f79b3",
input: "0x",
nonce: 55,
to: "0x4d5bbe7fbc80933ffa90ece988a764e41ee6d018",
transactionIndex: null,
value: 1234500000000000000
}
> eth.getTransactionReceipt("0xc7c63b67747c0c825229ce3d36d226423adb8cab6bebe12b6d5001e0dc3f79b3")
{
blockHash: "0xf0af8236ceec7ad1839d67c9934ab062a8d95fa1f88b06139f97dbdfbd1cd842",
blockNumber: 2234,
contractAddress: null,
cumulativeGasUsed: 21000,
from: "0xa7857047907d53a2e494d5f311b4b586dc6a96d2",
gasUsed: 21000,
logs: [],
root: "3280f47a0de1149ad5c5fda421faaf95f303da8a77e83c8ec6ac2b3d8ca27abc",
to: "0x4d5bbe7fbc80933ffa90ece988a764e41ee6d018",
transactionHash: "0xc7c63b67747c0c825229ce3d36d226423adb8cab6bebe12b6d5001e0dc3f79b3",
transactionIndex: 0
}
The transaction ID calculation is correct. For the signing, the arguments are still RLP encoded (the dummy "v" for EIP-155 is a bit special, see below).
Take this live transaction as an example. It has the following parameters.
nonce = 0 [RLP: 0x80]
gasPrice = 50000000000 wei (0x0BA43B7400) [RLP: 85 0BA43B7400]
gasLimit = 21000 (0x5208) [RLP: 82 5208]
to = 0x7917bc33eea648809c285607579c9919fb864f8f [RLP: 94 7917bc33eea648809c285607579c9919fb864f8f]
value = 1050000000000000 wei (0x03BAF82D03A000) [RLP: 87 03BAF82D03A000]
data = <empty> [RLP: 80]
v = 018080 (this is a place-holder value before signing, see EIP-155)
Then the input parameters for the hash is the RLP of the concatenation:
EB80850BA43B7400825208947917bc33eea648809c285607579c9919fb864f8f8703BAF82D03A00080018080
And the hash value for the signing is:
python3
>>> from Crypto.Hash import keccak
>>> keccak_hash=keccak.new(digest_bits=256)
>>> txn=bytearray.fromhex('EB80850BA43B7400825208947917bc33eea648809c285607579c9919fb864f8f8703BAF82D03A00080018080')
>>> keccak_hash.update(bytes(txn))
<Crypto.Hash.keccak.Keccak_Hash object at 0x10fb6e2e8>
>>> print(keccak_hash.hexdigest())
which gives the result
a4060d01d4add248db470b4121616cbe5b2015daf328809000ec9a1d0954d649
For the transaction ID, do Keccak hash on the final raw transaction bytes (RLP encoded as you mentioned, which are also readable from Etherscan) and it will give the same result as shown on Etherscan.
Best Answer
The procedure of generating the transaction is the same, but the value will always be pseudo random due to the nature of hash function. This post will be a good one to refer.
However if the network is public, given the transaction hash, it is possible to get the transaction details using the web3 api as documented here. It will return the address of the account where it came from.