Safe Practice of TRON Solidity Smart Contracts: Implement Random Numbers in the Contracts

Introduction

In blockchain, Solidity is a widely-used language to write many smart contracts that we see today (such as TRON smart contracts). Much has thus been learned by developers and users.

Random numbers on blockchains

As a popular segment of TRON DApps, games usually require random numbers to support their inner logic. Dice games, for example, generate random numbers through a random number algorithm. In theory, a good algorithm guarantees the absolute fairness of the game.

Difficulties to implement random numbers on a blockchain

Predictability

Use public on chain data as random numbers

TVM provides the following special functions to access public on chain data:

  • block.timestamp (uint): timestamp of the current block (measured in seconds) since unix epoch
  • block.coinbase (address): address of the SR that produces the current block
function airdrop()
private
view
returns(bool)
{
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp).add
(block.difficulty).add
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
(block.gaslimit).add
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
(block.number)

)));
if((seed - ((seed / 1000) * 1000)) < airDropTracker_)
return(true);
else
return(false);

}
Interface IFomo3d {
function airDropTracker_() external returns (uint256);
function airDropPot_() external returns (uint256);
function withdraw() external;
}
Contract Hack3dExample {
constructor() public payable {
// link to f3d contract instance
IFomo3d fomo3d = IFomo3d (0xa);
// Calculate seed
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp) +
(block.difficulty) +
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)) +
(block.gaslimit) +
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)) +
(block.number)
)));

uint256 tracker = fomo3d.airDropTracker_();
if((seed - ((seed / 1000) * 1000)) >= tracker) {
revert();
}
//do something to break fomo3d
selfdestruct(msg.sender);
}
}
function pickWinner() private {
address entropy1 = contestants[uint(block.coinbase) % totalTickets].addr;
address entropy2 = contestants[uint(msg.sender) % totalTickets].addr;
uint256 entropy3 = block.time;
bytes32 randHash = keccak256(entropy1 , entropy2 , entropy3 );

uint winningNumber = uint(randHash) % totalTickets;
address winningAddress = contestants[winningNumber].addr;
RaffleResult(raffleId, winningNumber, winningAddress, entropy1 , entropy2 , entropy3 , randHash);

// Start next raffle
raffleId++;
nextTicket = 0;
blockNumber = block.number;

// gaps.length = 0 isn't necessary here,
// because buyTickets() eventually clears
// the gaps array in the loop itself.

// Distribute prize and fee
winningAddress.transfer(prize);
feeAddress.transfer(fee);
}
  • The second is msg.sender = contestants [uint(msg.sender) % totalTickets].addr
  • The third is block.time.
  • msg.sender represents the address of the contract caller.
  • block.time can also be derived from that of the previous block, as the time period for block production on TRON is fixed.

BlockHash as a random number

As BlockHash is unknown before a block is generated, can it be used as the source of random numbers then? Let’s take a look at the following contract codes for generating random numbers:

function rand() public returns(uint256) {

uint256 random = uint256(keccak256(block.blockhash(block.number)));

return random%10;

}
  1. In the second transaction, contracts retrieve the current block’s height. Shall it exceeds the stored future block’s height, a pseudo-random number will be generated through the block’s blockhash.

Random number generation strategy based on hash-commit-reveal

hash-commit-reveal is considered by many contract developers the best implementation method for random numbers and has been widely applied to a large number of DApps. Let’s take a look at how it works.

  1. After the contract caller receives (commit, commitLastBlock, sig), send the specific transactions (as annotated below) to the smart contract.
  2. After the contract caller submits the transaction, the external oracle (secretSigner) sends reveal, the public commit value of the transaction, to the blockchain. The contract calculates random numbers like this: random_number=keccak256(reveal,block1.hash).

Summary

Blockchain is a decentralized system. Theoretically, the random numbers generated are fairer and more transparent than a centralized system but are more prone to hackers because of its decentralized environment and public algorithm. In addition, the remaining balance of the contract is also open. When the balance reaches a certain threshold, potential malicious behaviors from SR should be taken into consideration. Therefore, it is necessary to select a random number solution based on the scenario. In blockchains, there are a large number of random number scenarios, that are essential to the mass adoption of blockchain applications. It is safe to say that more developers and teams will partake in building and perfecting the random number generation mechanism of blockchains in the future.

References

https://www.freebuf.com/vuls/179173.html
http://www.jouypub.com/2018/7665609b0126606e2ae90ad7cfcdce8b/

For more information

Github: https://github.com/tronprotocol

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store