Patricio Palladino
patricio@nomiclabs.io
I want you to write a program that has to run in a concurrent environment under Byzantine circumstances where any adversary can invoke your program with any arguments of their choosing. The environment in which your program executes (and hence any direct or indirect environmental dependencies) is also under adversary control. If you make a single exploitable mistake or oversight in the implementation, or even in the logical design of the program, then either you personally or perhaps the users of your program could lose a substantial amount of money. Where your program will run, there is no legal recourse if things go wrong. Oh, and once you release the first version of your program, you can never change it. It has be right first time.
mapping(address => uint256) balances;
function sendEtherTo(address to, uint256 amount) {
require(balances[msg.sender] >= amount);
to.call.value(amount)();
balances[msg.sender] -= amount;
}
contract Attacker {
function attack() {
target.sendEtherTo(this, 1 ether);
}
function() payable {
attack();
}
}function createFunds(address beneficiary, uint256 value) public {
balances[beneficiary] += value;
}function createFunds(address beneficiary, uint256 value) public onlyOwner{
balances[beneficiary] += value;
}
address owner;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}function sendEtherTo(address to, uint256 amount) {
require(balances[msg.sender] - amount > 0);
balances[msg.sender] -= amount;
to.transfer(amount);
}function withdraw(uint256 _amount) public {
require(balances[msg.sender] >= _amount);
balances[msg.sender] -= _amount;
etherLeft -= _amount;
msg.sender.send(_amount);
}function becomePresident() payable {
require(msg.value >= price); // must pay the price to become president
president.transfer(price); // we pay the previous president
president = msg.sender; // we crown the new president
price = price * 2; // we double the price to become president
}function guess(uint8 n) public payable {
require(msg.value == 1 ether);
uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now));
if (n == answer) {
msg.sender.transfer(2 ether);
}
}function attack() public payable {
uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now));
victim.guess.value(1 ether)(answer);
}function play() public {
require(now > 1521763200 && neverPlayed == true);
neverPlayed = false;
msg.sender.transfer(1500 ether);
}Seguridad primero
Código modular
Claridad y buenos nombres
Reutilización de código
Tests automatizados
Runtime assertions
Code reviews y auditorias
No es un feature que se puede agregar despues.
Tiene que tenerse en cuenta desde el diseño del sistema
Modularización compartimentaliza
responsabilidades y fracciona la superficie de ataque
El código simple facilita su desarrollo, comprensión y análisis
Reutilizar código auditado y battle-tested
disminuye la posibilidad de errores
100% de code coverage signífica
que apenas estas tocando cada statement/condición/etc
Fallar lo antes posible, de forma explicita