1

When we make a transaction call, we get the transaction hash right away. As mentioned here we could not get transaction's hash inside the contract's function. Would it be good idea to set a variable of the contract with the transaction hash value right after it has been generated?

 > myContract.hello();
"0x41f6c6fbdfd4184172d61b390922270db087519137c43d3052fbad33876964f7"
> myContract.setUniqueHash("0x41f6c6fbdfd4184172d61b390922270db087519137c43d3052fbad33876964f7");

Goal: I want to use a unique hash value inside my contract as a key. Externally setting a unique value seems more efficient in gas wise.

[Q1] Inside geth console, is it possible to create an unique hash? If yes I could submit it into my contract as an argument instead of a transaction hash.

Would following might help? web3.sha3("Print(helloWorld)") as an unique hash. Worst case maybe I can add a file into ipfs and use its hash as key.

[Q2] Is there any way to create unique hash inside solidity?

  • A question about something related is "How to generate a random number" ethereum.stackexchange.com/q/191. You can use a similar technique to generate a unique hash. – Ismael Apr 18 '17 at 18:20
2

If the hash doesn't need to be perfectly random, instead you just want some guaranteed unique ID, you could sha3 a nonce or to be more abstract, with concatenation of data that's been sent with the transaction.

uint nonce;
...
bytes32 unique = sha3(block.number, msg.data, nonce++)`

It depends on what properties you need in the resulting hash.

sha3 can be used for generating owned indecies into mappings, like this owned strings example:

contract OwnedIndex {

    mapping (bytes32 => string) ownedString;

    function set(string _str)
    {
        // Generates a key unique to sender and string
        ownedString[sha3(msg.sender, _str)] = str;
    }

    function clear(string _str)
    {
        // Must be the origional sender to generate key to delete
        delete ownedString[sha3(msg.sender, _str)];
    }
}
  • Is it possible to call something like: "web3.sha3(block.number, msg.data, nonce++)" inside geth, I think it only accepts string? @o0ragman0o – alper Apr 19 '17 at 5:26
  • This seems working: web3.eth.sign(eth.accounts[0], web3.sha3("Some text"), nonce); nonce => web3.eth.getBlock(5).nonce right? @o0ragman0o – alper Apr 19 '17 at 11:20
  • 1
    Sorry I think I've led you astray with that question (now deleted). web3.sha3(...) should be all you need. You just might need to do a bit of research on generating unique ID's from pseudo-random sources. Perhaps just web3.sha3(Math.random()). – o0ragman0o Apr 19 '17 at 12:08
4

The answer to the question in the title is no, it is not possible to create a hash in Solidity that you are sure will be unique, at least given the possibility of block orphaning and reorgs.

Users can pass a nonce into the transaction, but unless you trust them, you can't be sure they won't pass the same one in twice. If you're making your ID entirely based on user-supplied data, they may maliciously attempt to get IDs that other users are expecting will be assigned to different data.

If you're not worried about reorgs, you can simply increment a number inside the contract. This number will uniquely identify a single record in any given block. However, if that block is orphaned, it may end up identifying a different record in the competing block that ends up in the longest chain. This may make it inconvenient to create an application that uses it, as you may have to handle the ID created by a transaction changing after you have already displayed it or processed it.

If the record you're creating must be unique in your contract based on the data it contains, you should simply hash the data in the contract to create an ID uniquely identifying it. Hashing is quite cheap compared to storing data, so the gas costs shouldn't normally be prohibitive. This also means you know what ID the record will have before you send the transaction, which can make it easier to keep track of.

If a record with the same content needs to be createable multiple times each with a new record, you may want to use a user-created nonce, but hash that with the user's address. Have the contract verify that it doesn't already have a record with that ID, and if it does throw an error. The nonce can be tracked in the application, or it can use something that won't normally accidentally collide, like a large, client-generated random number or a client-generated timestamp. That way although a user could create transactions that would normally get the same ID, a user can't maliciously create an ID that another user expects to be assigned to their record. This also preserves your application's ability to predict in advance what ID the transaction it is sending will get, unless your user tinkers with your application to confuse it on purpose, which in most cases will only hurt themselves.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.