mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-24 10:01:38 +00:00
Solidity - PT/BR Translation
This commit is contained in:
parent
c076537cf9
commit
f225f0cb31
913
pt-br/solidity-pt.html.markdown
Normal file
913
pt-br/solidity-pt.html.markdown
Normal file
@ -0,0 +1,913 @@
|
||||
---
|
||||
language: Solidity
|
||||
filename: learnSolidity.sol
|
||||
contribuidors:
|
||||
- ["Nemil Dalal", "https://www.nemil.com"]
|
||||
- ["Joseph Chow", ""]
|
||||
translators:
|
||||
- ["João Farias", "http://thatsabug.com/"]
|
||||
---
|
||||
|
||||
Solidity permite você programar para a [Ethereum]
|
||||
(https://www.ethereum.org/), uma máquina virtual baseada na tecnologia blockhain
|
||||
para criação e execução de contratos inteligentes, sem necessidade de partes
|
||||
centralizadas ou de confiança.
|
||||
|
||||
Solidity é uma linguagem de contratos estaticamente tipaada com similaridade com
|
||||
Javascript e C. Como objetos em programação orientada a objetos, cada contrato
|
||||
possue variáveis de estado, funções e tipos de dados comuns. Funcionalidades
|
||||
particulares de contratados incluem cláusuras modificadoras (guarda), notifica
|
||||
dores de eventos para listerners e variáveis globais customizadas.
|
||||
|
||||
|
||||
Exemplos de contratos Ethereum incluem crowdfunding, votações e audições cegas.
|
||||
|
||||
Erros em código Solidity causam grandes riscos e custos; portanto, você
|
||||
deve ser muito cuidado com teste e divulgação. DEVIDO ÀS CONSTANTES MUDANÇAS
|
||||
NO ETHEREUM, ESTE DOCUMENTOS PROVAVELMENTE NÃO ESTARÁ ATUALIZADO, VOCÊ DEVE
|
||||
ACOMPANHAR A CHATROOM DO SOLIDITY E O BLOG DO ETHEREUM PARA NOTÍCIAS ATUALIZADAS.
|
||||
TODO CÓDIGO AQUI É ENTREGUE COMO ESTÁ, COM SUBSTANCIAL RISCO DE ERRROS E PADRÕES
|
||||
DE CÓDIGO DEPRECADOS.
|
||||
|
||||
Diferentemente de outros tipo de código, você também deve adicionar padrões
|
||||
como pausa, deprecação e retração para reduzir riscos. Este documento discute
|
||||
sintaxe, então, muito padrões populares são excluídos.
|
||||
|
||||
Como Solidity e Ethereum ainda estão sob desenvolvimento, funcionalidades beta
|
||||
e experimentais são tipicamente marcadas e sujeitas à mudanças. Pull requests
|
||||
são bem-vindos.
|
||||
|
||||
```javascript
|
||||
// Primeiramente, um contrato de um Banco simples
|
||||
// Permite depósitos, retiradas e checagens de saldo
|
||||
|
||||
// banco_simples.sol (note a extensão .sol)
|
||||
|
||||
/* **** INCICIO DO EXEMPLO **** */
|
||||
|
||||
// Declare a versão do compilador.
|
||||
pragma solidity ^0.4.2;
|
||||
|
||||
// Inicie com comentários Natspec (as três barras)
|
||||
// usados para documentação - e como dados descritivos para elementos/ação de UI
|
||||
|
||||
/// @title BancoSimples
|
||||
/// @author nemild
|
||||
|
||||
/* 'contrato' tem similadirades com 'classes' em outras linguagens (variáveis de
|
||||
class, herança, etc.) */
|
||||
|
||||
contract BancoSimples { // CamelCase
|
||||
// Declare variáveis de estado fora da função, para persistí-la durante a
|
||||
// duração do contrato
|
||||
|
||||
// dicionário que mapeia endereços para saldos
|
||||
// tenha cuidado sobre ataques de overflow com números
|
||||
|
||||
mapping (address => uint) private saldos;
|
||||
|
||||
// "private" significa que outros contratos não podem acessar saldos
|
||||
// diretamente, mas o dado ainda é visível para outras partes da blockchain
|
||||
|
||||
address public dono;
|
||||
|
||||
// ´public´ é legível (mas sem acesso de escrita) por usuários e contratos
|
||||
|
||||
// Eventos - ações públicas para ouvintes externo
|
||||
event LogRealizacaoDeDeposito(address numeroDaConta, uint quantidade);
|
||||
|
||||
// Construtor, pode receber uma ou várias variáveis; apenas uma opção é
|
||||
// permitidas
|
||||
|
||||
function BancoSimples() {
|
||||
// msg dá detalhes sobre a mensagem mandada pelo contrato
|
||||
// msg.sender é um chamador do contrato (endereço do criador do
|
||||
// contrato)
|
||||
|
||||
dono = msg.sender;
|
||||
}
|
||||
|
||||
/// @notice Deposita ether no banco
|
||||
/// @return O saldo do usuário após o depósito
|
||||
|
||||
function deposito() public returns (uint) {
|
||||
saldos[msg.sender] += msg.value;
|
||||
|
||||
// Sem necessidade de "this." ou "self." para variáveis de estado
|
||||
// todos as variáveis são inciadas com seu valor default
|
||||
|
||||
LogRealizacaoDeDeposito(msg.sender, msg.value); // dispara evento
|
||||
|
||||
return saldos[msg.sender];
|
||||
}
|
||||
|
||||
/// @notice Retira ether do banco
|
||||
/// @dev Isto não retorna nenhum ether excendente
|
||||
/// @param quantidadeDeRetirada quantidade que você quer retirar
|
||||
/// @return O saldo restante do usuário
|
||||
function retirada(uint quantidadeDeRetirada) public returns (uint saldoRestate) {
|
||||
if(saldos[msg.sender] >= quantidadeDeRetirada) {
|
||||
|
||||
// Observe como deduzimos o saldo imediatamente, antes de enviar -
|
||||
// devido ao risco de uma chamada recursiva que permite o chamador
|
||||
// pedir um valor maior que seu saldo
|
||||
|
||||
saldos[msg.sender] -= quantidadeDeRetirada;
|
||||
|
||||
if (!msg.sender.send(quantidadeDeRetirada)) {
|
||||
// incremente de volta só se falhar, como pode estar enviando
|
||||
// para o contrato que substituiu 'enviar' no final
|
||||
// do recebimento
|
||||
saldos[msg.sender] += quantidadeDeRetirada;
|
||||
}
|
||||
}
|
||||
|
||||
return saldos[msg.sender];
|
||||
}
|
||||
|
||||
/// @notice Retorna o saldo
|
||||
/// @return O saldo do usuário
|
||||
// 'constant' evita que a função edite variáveis de estado
|
||||
// permite a função executar localmente/fora da blockchain
|
||||
function saldo() constant returns (uint) {
|
||||
return saldos[msg.sender];
|
||||
}
|
||||
|
||||
// Função de fallback - Chamada se outras funções não forem chamadas ou
|
||||
// se ether sem dados forem enviados
|
||||
// Tipicamente chamada quando dados inválidos são enviados
|
||||
// Adicionada para que ether enviado neste contrato seja revertido se o
|
||||
// contrato falhar. Se não existisse, o dinheiro do enviante é transferido
|
||||
// para o contrato
|
||||
function () {
|
||||
throw; // 'throw' reverte o estao para antes da chamada
|
||||
}
|
||||
}
|
||||
// ** FIM DO EXEMPLO **
|
||||
|
||||
// Agora, o básico de Solidity
|
||||
|
||||
|
||||
//1 TIPO DE DADOS E MÉTODOS ASSOCIADOS
|
||||
// uint é usado para quantidade de moeda (não existem doubles ou floats)
|
||||
// e para datas (no sistema de tempo Unix)
|
||||
|
||||
uint x;
|
||||
|
||||
// int de 256 bits, não pode ser mudado após sua instanciação
|
||||
int constant a = 8;
|
||||
int256 constant a = 8; // mesmo efeito, mas aqui os 256 bits são explícitos
|
||||
uint constant VERSÃO_ID = 0x123A1; // uma constante hexadecimal
|
||||
|
||||
// com 'constant', o compilador substitui cada ocorrência com o valor
|
||||
|
||||
// Para int e uint, é possível determinar o espaço explicitamente, em intervalos
|
||||
// de 8 a 256, e.g., int8, int16, int24
|
||||
uint8 b;
|
||||
int64 c;
|
||||
uint248 e;
|
||||
|
||||
// Cuidado contra overflows, e proteja-se contra esse tipo de ataque
|
||||
|
||||
// Não há funções randômicas padrão, use outros contratos para este objetivo
|
||||
|
||||
// Casting de tipo
|
||||
int x = int(b);
|
||||
|
||||
bool b = true; // ou então 'var b = true;' para inferição de tipo
|
||||
|
||||
// Endereços - comportam 20 bytes/160 bits endereços Ethereum
|
||||
// Não permite operações aritiméticas
|
||||
address public dono;
|
||||
|
||||
// Tipos de contas:
|
||||
// Conta de contrato: endereço criado ao criar (função do endereço do criador,
|
||||
// número da transação)
|
||||
// Conta externa: (pessoa/entidade externa): endereç criado a partir de chave
|
||||
// pública
|
||||
|
||||
// Adicione o campo 'public' para indicar visibilidade pública/externa
|
||||
// um getter é automaticamente criado, mas NÃO um setter
|
||||
|
||||
// Todos os endereços podem enviar ether
|
||||
dono.send(ALGUM_SALDO); // returna falso caso falhe
|
||||
if (dono.send) {} // LEMBRE-SE: encapsule num 'if', dado que endereços de
|
||||
// contrato tem funções executadas no envio e estas podem falhar
|
||||
//Também certifique-se que os saldos deduzidos ANTES de tentar enviar, dado que
|
||||
// há um risco de chamada recursiva que pode drenar um contrato
|
||||
|
||||
// pode sobrescrever seu próprio
|
||||
|
||||
// Pode verificar o saldo
|
||||
dona.balance; // o saldo do dono (usuário ou contrato)
|
||||
|
||||
// Bytes permitidos de 1 a 32
|
||||
byte a; // byte é o mesmo que bytes1
|
||||
bytes2 b;
|
||||
bytes32 c;
|
||||
|
||||
// Bytes dinamicamente criados
|
||||
|
||||
bytes m; // Um array especial, mesmo que byte[] (mas mais comprimido)
|
||||
|
||||
// Mais custoso que byte1-byte32, então, prefira estes quando possível
|
||||
|
||||
// mesmo que bytes, mas não permite verificar tamanho ou acesso por indíce (por
|
||||
// enquanto)
|
||||
|
||||
string n = "oi"; // guardado em UTF8, note as aspas duplas, não simples
|
||||
|
||||
// funções de string serão adicionadas no futuro
|
||||
// prefira bytes32/bytes, dado que UTF8 usa mais espaço
|
||||
|
||||
// Inferência de tipo
|
||||
// var não infere tipos baseados na primeira atribuição,
|
||||
// não pode ser usado em paramêtros de funções
|
||||
|
||||
var a = true;
|
||||
|
||||
// use com cuidado, inferência pode resultar em tipos errados
|
||||
// e.g., um int8, quando um contador precisa de int16
|
||||
|
||||
// var pode ser usado para assinalar uma função a uma variável
|
||||
function a(uint x) returns (uint) {
|
||||
return x * 2;
|
||||
}
|
||||
var f = a;
|
||||
f(22); // chamada
|
||||
|
||||
// por padrão, todos os valores são inicializados com 0
|
||||
|
||||
// Delete pode ser chamada na maioria dos tipos
|
||||
// (NÃO destroi o valor, mas retorna para o valor 0, o incial)
|
||||
|
||||
uint x = 5;
|
||||
|
||||
// Desestruturação/Tuplas
|
||||
(x, y) = (2, 7); // assinada/troca múltiplos valores
|
||||
|
||||
// 2. ESTRUTURAS DE DADOS
|
||||
// Arrays
|
||||
|
||||
bytes32[5] apelidos; // array estático
|
||||
bytes32[] nomes; // array dinâmico
|
||||
uint novoTamanho = nomes.push("João"); // adicionando retorna o novo tamanho do
|
||||
|
||||
// Tamanho
|
||||
nomes.length; // pega o tamanho
|
||||
nomes.length = 1; // tamanhos pode ser alterados (para arrays dinâmicos)
|
||||
|
||||
// arrays multidimensionais
|
||||
uint x[][5]; // array com 5 arrays dinâmicos como elementos (ordem da maioria
|
||||
// das linguagens)
|
||||
|
||||
// Dicionários (qualquer tipo para qualquer tipo)
|
||||
mapping (string => uint) public saldos;
|
||||
saldos["charles"] = 1;
|
||||
console.log(saldos["ada"]); // é 0, toda chave não assinalada retorna zero
|
||||
// 'public' permite o seguinte contrato
|
||||
nomeDoContrato.saldos("charles"); // retorna 1
|
||||
// 'public' cria um getter (mas não um setter) como o seguinte
|
||||
function saldos(string _conta) returns (uint saldo) {
|
||||
return saldos[_conta];
|
||||
}
|
||||
|
||||
// Mapeamentos aninhados
|
||||
mapping (endereco => mapping (endereco => uint)) public guardioes;
|
||||
|
||||
// Para deletar
|
||||
delete saldos["John"];
|
||||
delete saldos; // assinala zero para todas as chaves
|
||||
|
||||
// Diferentemente de outras linguages, NÃO É POSSÍVEL iterar sobre todos os
|
||||
// elementos de um mapeamento, sem saber previamente as chaves - é possível
|
||||
// construir estruturas de dados personalizadas para fazer isso
|
||||
|
||||
// Structs e enums
|
||||
struct Banco {
|
||||
address dono;
|
||||
uint saldo;
|
||||
}
|
||||
Banco b = Banco({
|
||||
dono: msg.sender,
|
||||
saldo: 5
|
||||
});
|
||||
// ou
|
||||
Banco c = Banco(msg.sender, 5);
|
||||
|
||||
c.quantidade = 5; // cria novo valor
|
||||
delete b;
|
||||
// assinala todos os valores do enum para zero, exceto mapeamentos
|
||||
|
||||
// Enums
|
||||
enum Estado { Criado, Travado, Inativo }; // geralmente usado para máquina de
|
||||
// estados
|
||||
Estado public estado; // Declara variável para enum
|
||||
estado = Estado.Criado;
|
||||
// enums podem ser explicitamente convertidas em ints
|
||||
uint estadoCriado = uint(Estado.Criado); // 0
|
||||
|
||||
// Localização de dados: Memória vs. disco vs. pilha - todos os tipos complexos
|
||||
// (arrays, structs) tem uma localização de dados
|
||||
// 'memória' não é persistida, 'disco' é
|
||||
// Padrão é 'disco' para variáveis locais e de estado; 'memória' para paramêtros
|
||||
// de função. Pilha guarda pequena variáveis locais
|
||||
|
||||
// a maioria dos tipos podem ter sua localização de dados explicitamente assinalos
|
||||
|
||||
// 3. Operações simples
|
||||
// Comparações, operadores binários e aritimétricos são providos
|
||||
// exponenciação: **
|
||||
// ou exclusivo: ^
|
||||
// negação binária: ~
|
||||
|
||||
// 4. Variáveis Globais de nota
|
||||
// ** this **
|
||||
this; // endereço do contrato
|
||||
// geralmente usado no final do contrato para enviar o saldo restante às partes
|
||||
this.balance;
|
||||
this.algumFuncao(); // chamada de função externa via call, não via jump interno
|
||||
|
||||
// ** msg - Mensagem corrente recebida pelo contrato ** **
|
||||
msg.sender; // endereço do enviador
|
||||
msg.value; // quantidade de ether provida para este contrato em wei
|
||||
msg.data; // bytes, todos os dados da chamada
|
||||
msg.gas; // gas restante
|
||||
|
||||
// ** tx - Esta transação **
|
||||
tx.origin; // endereço do enviador da transação
|
||||
tx.gasprice; // valor do gas da transação
|
||||
|
||||
// ** block - Informação do bloco corrente **
|
||||
now; // tempo corrente (aproxiamdo), substituto para block.timestamp
|
||||
//(usa tempo do Unix)
|
||||
block.number; // número do bloco corrente
|
||||
block.difficulty; // dificuldade do bloco corrente
|
||||
block.blockhash(1); // retorna bytes32, só funciona para os 256 blocos mais
|
||||
//recentes
|
||||
block.gasLimit();
|
||||
|
||||
// ** storage - Hash de disco persistente **
|
||||
storage['abc'] = 'def'; // mapea palavras de 256 bits em palavras de 256 bits
|
||||
|
||||
|
||||
// 4. FUNÇÕES E MAIS
|
||||
// A. Funções
|
||||
// Funções simples
|
||||
function incremento(uint x) returns (uint) {
|
||||
x += 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Funções podem retornar muito argumentos, e podem especificar argumentos
|
||||
// retornados sem necessidade de explicitamente usar return
|
||||
function incremento(uint x, uint y) returns (uint x, uint y) {
|
||||
x += 1;
|
||||
y += 1;
|
||||
}
|
||||
// Chamando a função anterior
|
||||
uint (a,b) = incremento(1,1);
|
||||
|
||||
// 'constant' indica que uam função não altera variáveis persistidas
|
||||
// Funções constantes são executadas localmente, não na blockchain
|
||||
uint y;
|
||||
|
||||
function incremento(uint x) constant returns (uint x) {
|
||||
x += 1;
|
||||
y += 1; // Esta linha deve falhar
|
||||
// y é uma variável de estado e não pode ser alterada por uma função local
|
||||
}
|
||||
|
||||
// 'Especificadores de visibilidade de funções'
|
||||
// Estes podem substituitir 'constante', incluíndo:
|
||||
// public - visbilidade externa e interna (padrão)
|
||||
// private - apenas visível no contrato corrente
|
||||
// internal - apenas visível no contrato corrente e seus derivados
|
||||
|
||||
// Functions hosteada - e pode ser assinalada para variável
|
||||
function a() {
|
||||
var z = b;
|
||||
b();
|
||||
}
|
||||
|
||||
function b() {
|
||||
|
||||
}
|
||||
|
||||
// Prefira loops sobre recursões (pilha de chamada é no máximo 1024)
|
||||
|
||||
// B. Eventos
|
||||
// Eventos podem notificar partes externas; facilmente buscáveis e acessáveis
|
||||
// de fora da blockchain (com clientes leves)
|
||||
// tipicamente declarados após os parâmetros do contrato
|
||||
|
||||
// Tipicamente, com letra maiúscula - e adicione Log na frente para
|
||||
// ser explicito e previnir confusão na chamada da função
|
||||
|
||||
// Declaração
|
||||
event LogEnvio(address indexed de, address indexed para, uint quantidade);
|
||||
// Observe a letra maíscula no início do nome
|
||||
|
||||
// Chamada
|
||||
Envio(de, para, quantidade);
|
||||
|
||||
// Para partes externas (um contrato ou entidade externo), observe:
|
||||
Coin.Envio().watch({}, '', function(erro, resultado) {
|
||||
if (!erro) {
|
||||
console.log("Moeda transferida: " + resultado.args.quantidade +
|
||||
" moedas enviadas de " + resultado.args.de +
|
||||
" para " + resultado.args.para + ".");
|
||||
console.log("Saldo atual:\n" +
|
||||
"Enviador: " + Coin.balances.call(resultado.args.de) +
|
||||
"Recebedor: " + Coin.balances.call(resultado.args.para));
|
||||
}
|
||||
}
|
||||
// Paradigma comum para um contrato depender de outro (e.g., um contrato que
|
||||
// depende da taxa de troca provida por outro)
|
||||
|
||||
// C. ModifiCadores
|
||||
// MOdificadores validam entradas de funções, como saldo mínimo e autorização
|
||||
// do usuário; semelhantes a guardas em outras linguagens
|
||||
|
||||
// '_' (subtraço) geralmente incluído como última linha do corpo, indica que a
|
||||
// função sendo chamada deve ser colocada ali
|
||||
modifier apenasDepois(uint _tempo) { if (agora <= _tempo) throw; _ }
|
||||
modifier apenasDono { if (msg.sender == dono) _ }
|
||||
// geralmente usado para máquina de estado
|
||||
modifier apenasSeEmEstado (Estado estadoCorrente)
|
||||
{ if (estadoCorrente != Estado.A) _ }
|
||||
|
||||
// Concatenado logo após a chamada da função
|
||||
function mudeDona(novoDono)
|
||||
apenasDepois(algumTempo)
|
||||
apenasDono()
|
||||
apenasSeEmEstado(Estado.A)
|
||||
{
|
||||
dono = novoDono;
|
||||
}
|
||||
|
||||
// subtração pode ser incluído antes do final do corpo, mas retorno explícitos
|
||||
// pode ser ignorado, então, tome cuidado
|
||||
modifier chequeValor(uint quantidade) {
|
||||
_
|
||||
if (msg.value > quantidade) {
|
||||
uint quantidadeASerDevolvida = quantidade - msg.value;
|
||||
if (!msg.sender.send(quantidadeASerDevolvida)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. BRANCHES E LOOPS
|
||||
|
||||
// Todas as lógicas básicas de bloco funcionam - incluindo if/else,
|
||||
// while, break, continue, return - mas não há switch
|
||||
|
||||
// A sintaxe é semelhante a Javascript, mas sem conversão de tipos
|
||||
// de não-booleanos para booleanos (operadores de comparação precisam
|
||||
// utilizar valores booleanos)
|
||||
|
||||
// Loops que dependem o comportamento do usuário exigem cuidado - dado
|
||||
// que contratos tem uma quantidade máxima de gas para cada bloco de
|
||||
// de código - falhas acontecerão caso ele seja excedido
|
||||
// Por exemplo:
|
||||
for(uint x = 0; x < listaDeEnderecoDeRefundo.length; x++) {
|
||||
if (!listaDeEnderecoDeRefundo[x].send(ALGUMA_QUANTIDADE)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Dois erros acima:
|
||||
// 1. Uma falha no enviar para o loop completamente, travando dinheiro
|
||||
// 2. Este loop pode ser abitrariamente longo (basado na quando que
|
||||
// o usuário precisa de refundo), portanto, pode falhar quando exceder
|
||||
// a quantidade máxima de gas do bloco
|
||||
// Ao invés disso, você deve deixar as pessoas retirarem
|
||||
// individualmente de suas subcontas e marcarem a retirada
|
||||
|
||||
|
||||
// 7. OBJETOS/CONTRATOS
|
||||
|
||||
// A. Chamando um contrato externo
|
||||
contract FonteDeInformacoes {
|
||||
function info() returns (uint ret) { return 42; }
|
||||
}
|
||||
|
||||
contract Consumidor {
|
||||
FonteDeInformacoes fonte; // aponta para um contrato na blockchain
|
||||
|
||||
// Assinala variável para uma instância do contrato
|
||||
function setFonte(address endereco) {
|
||||
// Cast automático, cuidado; construtor não é chamado
|
||||
fonte = FonteDeInformacoes(endereco);
|
||||
}
|
||||
|
||||
// Assinala variável para uma nova instância do contrato
|
||||
function createNewFeed() {
|
||||
fonte = new FonteDeInformacoes(); // nova instância criada
|
||||
// construtor é chamado
|
||||
}
|
||||
|
||||
function chameFonte() {
|
||||
// último parenteses chama o contrato, podendo adicionar
|
||||
// opcionalmente valores ou gas
|
||||
fonte.info.value(10).gas(800)();
|
||||
}
|
||||
}
|
||||
|
||||
// B. Herança
|
||||
|
||||
// Ordem importa, último contrato herdado (i.e., 'def') pode
|
||||
// sobrescrever partes de contratos previamente herdados
|
||||
contract MeuContratdo is abc, def("um argumento personalizado def") {
|
||||
|
||||
// sobrescrevendo função
|
||||
function z() {
|
||||
if (msg.sender == dono) {
|
||||
def.z(); // chama função sobrescrita de def
|
||||
super.z(); // chama função do pai imeadiato
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// função abstrata
|
||||
function umaFuncaoAbstrata(uint x);
|
||||
// não pode ser compilada, usada em contratos base/abstratos que
|
||||
// então, a implementam
|
||||
|
||||
// C. Import
|
||||
|
||||
import "filename";
|
||||
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol";
|
||||
|
||||
// 'Import' está sobre desenvolvimento
|
||||
// Atualmente não pode ser usada na linha de comando
|
||||
|
||||
|
||||
// 8.OUTRAS PALAVRAS-CHAVE
|
||||
|
||||
// A. Throwing
|
||||
// Throwing
|
||||
throw; // reverte estado e dinheiro NÃO-USADO é devolvido ao usuários
|
||||
// Atualmente não pode ser capturado
|
||||
|
||||
// Um padrão de design comum é:
|
||||
if (!endereco.send(123)) {
|
||||
throw;
|
||||
}
|
||||
|
||||
// B. Selfdestruct
|
||||
// auto-destroe o contrato corrente, enviando fundos para o endereço
|
||||
// (geralmente o criador)
|
||||
selfdestruct(ALGUM_ENDERECO);
|
||||
|
||||
// remove disco/código dos blocos corrente e futuros
|
||||
// ajuda clientes leves, mas dados persistidos continuam no blockchain
|
||||
|
||||
// Padrão comum, permite ao dono finalizar o contrato e receber fundos
|
||||
// restantes
|
||||
function remover() {
|
||||
if(msg.sender == criador) { // Apenas o criador do contrato pode
|
||||
// fazer isso
|
||||
selfdestruct(criador); // Inativa o contrato e retorna os fundos
|
||||
}
|
||||
}
|
||||
|
||||
// Talvez queria desativar o contrato manualmente, ao invés de usar
|
||||
// selfdestruct (ether enviado para contratos selfdestructed é perdido)
|
||||
|
||||
|
||||
// 9. NOTAS SOBRE DESIGN DE CONTRATOS
|
||||
|
||||
// A. Obfuscação
|
||||
// Todas as variáveis são publicamente visíveis na blockchain, então
|
||||
// qualquer coisa privada precisa ser obfuscada (e.g., hash com segredo)
|
||||
|
||||
// Passo-a-pass: 1. Comprometa-se com algo, 2. Revele compromisso
|
||||
sha3("quantidade_de_lance", "algum segredo"); // compromisso
|
||||
|
||||
// chame a função reveal (revelar) do contrato no futuros
|
||||
// mostrando o lance mais o segredo para foi hasheado com SHA3
|
||||
reveal(100, "meuSegredo");
|
||||
|
||||
// B. Otimização de disco
|
||||
// Escrever na blockchain pode ser caro, dado que os dados são guardados
|
||||
// para sempre. É encorajado que contratos inteligentes usem memória (
|
||||
// enventualmente, compilação será melhor, mas por enquanto é benéfico
|
||||
// usar estruturas de dados simples - armazenando minimamente na
|
||||
// blockchain)
|
||||
|
||||
// Custo pode ser alto para item como arrays multidimensionais
|
||||
// (custo para guardar os dados - não declarar variáveis)
|
||||
|
||||
// C. Acesso de dados da blockchain
|
||||
|
||||
// Não pode restringir humanos ou computadores de ler os conteúdos
|
||||
// de transações ou estado de transações
|
||||
|
||||
// Enquanto 'private' previne outros *contratos* de ler dados ]
|
||||
// diretamente - qualquer outra parte ainda pode ler dados da blockchain
|
||||
|
||||
// Todos os dados são armazedos na blockchain, para que qualquer um
|
||||
// possa observar dados antigos e mudanças
|
||||
|
||||
// D. Jobs Cron
|
||||
// Contratos deve ser manualmente chamados para lidar com agendamentos
|
||||
// baseados em tempo; podendo criar código externo para pingar
|
||||
// regularmente ou prover incentivos (ether) para outros fazê-lo
|
||||
|
||||
// E. Padrão Observador
|
||||
// O Padrão Observador permite que você registre um inscritor e
|
||||
// registre uma função a ser chamada pelo Oráculo (nota, Oráculos pagam
|
||||
// pela ação executada). Similarmente à subscrição em Pub/sub
|
||||
|
||||
// Este é um contrato abstrato, tanto as classes cliente como a
|
||||
// servidor importam o cliente que deve ser implementado
|
||||
contract AlgumOraculoCallback {
|
||||
function OraculoCallback(int _valor, uint _tempo, bytes32 info) external;
|
||||
}
|
||||
|
||||
contract AlgumOráculo {
|
||||
AlgumOraculoCallback[] callbacks; // array com todos os inscritos
|
||||
|
||||
// Registra inscrito
|
||||
function addInscrito(AlgumOraculoCallback a) {
|
||||
callbacks.push(a);
|
||||
}
|
||||
|
||||
function notificar(valor, tempo, info) private {
|
||||
for(uint i = 0;i < callbacks.length; i++) {
|
||||
// todos os inscritos precisam implementar AlgumOraculoCallback
|
||||
callbacks[i].OraculoCallback(valor, tempo, info);
|
||||
}
|
||||
}
|
||||
|
||||
function facaAlgo() public {
|
||||
// Código para fazer algo
|
||||
|
||||
// Notifica todos os inscrito
|
||||
notificar(_valor, _tempo, _info);
|
||||
}
|
||||
}
|
||||
|
||||
// Agora, seu contrato cliente pode addInscrito importando
|
||||
// AlgumOraculoCallback e registrando algum Oráculo
|
||||
|
||||
// F. Máquinas de estado
|
||||
// veja o exemplo abaixo para o enum Estado e o modificador noEstado
|
||||
|
||||
// *** EXEMPLO: Um exemplo de crowdfunding example (similar ao
|
||||
// Kickstarter) ***
|
||||
// ** INCIO DO EXEMPLO **
|
||||
|
||||
// FundadorDoCrowdFunding.sol
|
||||
|
||||
/// @title FundadorDoCrowdFunding
|
||||
/// @author nemild
|
||||
contract FundadorDoCrowdFunding {
|
||||
// Variáveis assinaladas na crição pelo criador
|
||||
address public criador;
|
||||
address public recipiente; // criador pode ser diferente do Recipiente
|
||||
uint public minALevantar; // requisito para pagar, pelo contrário
|
||||
// os doadores recebem o dinheiro de volta
|
||||
string urlDaCampanha;
|
||||
byte constant versao = 1;
|
||||
|
||||
// Estruturas de dados
|
||||
enum Estado {
|
||||
LevantandoFundos,
|
||||
RefundoExpirado,
|
||||
Sucesso
|
||||
}
|
||||
struct Contribuicao {
|
||||
uint quantidade;
|
||||
address contribuidor;
|
||||
}
|
||||
|
||||
// Variáveis de Estado
|
||||
State public estado = Estado.LevantandoFundos; // incializado na criação
|
||||
uint public totalLevantado;
|
||||
uint public levantadoPor;
|
||||
uint public completadoEm;
|
||||
Contribution[] contribuidores;
|
||||
|
||||
event LogRecebimentoDeFundos(address endereco,
|
||||
uint quantidade,
|
||||
uint totalAtual);
|
||||
event LogFundosPagos(address enderecoDoRecebedor);
|
||||
|
||||
modifier noEstado(Estado _estado) {
|
||||
if (estado != _estado) throw;
|
||||
_
|
||||
}
|
||||
|
||||
modifier eOCriador() {
|
||||
if (msg.sender != criador) throw;
|
||||
_
|
||||
}
|
||||
|
||||
// Aguarda 6 meses após o final do contrato para destruí-lo
|
||||
modifier noFimDoContrato() {
|
||||
if(!((estado == Estado.RefundoExpirado || estado == Estado.Sucesso) &&
|
||||
completadoEm + 6 months < now)) {
|
||||
throw;
|
||||
}
|
||||
_
|
||||
}
|
||||
|
||||
function FundadorDoCrowdFunding(
|
||||
uint tempoEmHorasParaFundraising,
|
||||
string _urlDaCampanha,
|
||||
address _recipiente,
|
||||
uint _minALevantar)
|
||||
{
|
||||
criador = msg.sender;
|
||||
recipiente = _recipiente;
|
||||
urlDaCampanha = _urlDaCampanha;
|
||||
minALevantar = _minALevantar;
|
||||
levantadoPor = now + (tempoEmHorasParaFundraising * 1 hours);
|
||||
}
|
||||
|
||||
function contribuir()
|
||||
public
|
||||
noEstado(Estado.LevantandoFundos)
|
||||
{
|
||||
contribuidores.push(
|
||||
Contribuicao({
|
||||
quantidade: msg.value,
|
||||
contribuidor: msg.sender
|
||||
}) // use array, para podermos iterar
|
||||
);
|
||||
totalLevantado += msg.value;
|
||||
|
||||
LogRecebimentoDeFundos(msg.sender, msg.value, totalRaised);
|
||||
|
||||
verifiqueSeLevantamentoFoiCompletadoOuExpirado();
|
||||
return contribuicoes.length - 1; // retorna id
|
||||
}
|
||||
|
||||
function verifiqueSeLevantamentoFoiCompletadoOuExpirado() {
|
||||
if (totalLevantado > minALevantar) {
|
||||
estado = Estado.Sucesso;
|
||||
pagar();
|
||||
|
||||
// pode incentivar enviador que iniciou a mudanção de estado
|
||||
} else if ( now > levantadoPor ) {
|
||||
estado = Estado.RefundoExpirado; // backers podem coletar
|
||||
// o fundo chamando receberRefundo(id)
|
||||
}
|
||||
completadoEm = now;
|
||||
}
|
||||
|
||||
function pagar()
|
||||
public
|
||||
emEstado(Estado.Sucesso)
|
||||
{
|
||||
if(!recipiente.send(this.balance)) {
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
LogFundosPagos(fundRecipient);
|
||||
}
|
||||
|
||||
function receberRefundo(id)
|
||||
public
|
||||
emEstado(Estado.RefundoExpirado)
|
||||
{
|
||||
if (contribuicoes.length <= id || id < 0 || contribuicoes[id].amount == 0 ) {
|
||||
throw;
|
||||
}
|
||||
|
||||
uint quantidadeDeRefundo = contribuicoes[id].amount;
|
||||
contribuicoes[id].amount = 0;
|
||||
|
||||
if(!contribuicoes[id].contribuidor.send(quantidadeParaEnviar)) {
|
||||
contribuicoes[id].amount = quantidadeParaEnviar;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function removerContrato()
|
||||
public
|
||||
eOCriador()
|
||||
noFimDoContrato()
|
||||
{
|
||||
selfdestruct(msg.sender);
|
||||
// criador recebe todo o dinheiro restante{
|
||||
|
||||
}
|
||||
|
||||
function () { throw; }
|
||||
}
|
||||
// ** FIM DO EXEMPLO **
|
||||
|
||||
// 10. OUTRAS FUNÇÕES NATIVAS
|
||||
|
||||
// Unidades monetárias
|
||||
// Moeda é definida usando wei, menor quantidade de ether
|
||||
uint quantidadeMin = 1 wei;
|
||||
uint a = 1 finney; // 1 ether == 1000 finney
|
||||
// Para outras unidades, veja: http://ether.fund/tool/converter
|
||||
|
||||
// Unidades temporais
|
||||
1 == 1 second // segundos
|
||||
1 minutes == 60 seconds // Minutos
|
||||
|
||||
// Pode multiplicar uma variável de tempo, dado que unidades não são guardadas
|
||||
// na variável
|
||||
uint x = 5;
|
||||
(x * 1 days); // 5 dias
|
||||
|
||||
// Cuidado com o salto de segundos / anos com declarações de igualdade para o tempo
|
||||
// (em vez disso, prefira maior que / menor que)
|
||||
|
||||
// Criptografia
|
||||
// Todas as string passadas são concatenadas antes de realizar hashing
|
||||
sha3("ab", "cd");
|
||||
ripemd160("abc");
|
||||
sha256("def");
|
||||
|
||||
// 11. Segurança
|
||||
|
||||
// Bugs são desastrosos para contratos Ethereum - até padrões Solidity populares
|
||||
// podem ser considerados anti-padrões
|
||||
|
||||
// Veja links para segurança no final deste documento
|
||||
|
||||
// 12. FUNÇÕES DE BAIXO NÍVELS
|
||||
// call - baixo nível, geralmente não usada, não tem segurança de tipos
|
||||
booleanSucesso = algumEnderecoDeContrato.call('nome_da_funcao', 'arg1', 'arg2');
|
||||
|
||||
// callcode - Código no endereço alvo executado no *contexto* do contrato
|
||||
// de chamada. Fornece funcionalidade de biblioteca
|
||||
algumEnderecoDeContrato.callcode('nome_da_funcao');
|
||||
|
||||
|
||||
// 13. NOTAS DE ESTILO
|
||||
// Baseado no guia de estilo PEP8 do Python
|
||||
|
||||
// Resumo rápido:
|
||||
// 4 espaços para identação
|
||||
// Duas linhas separam declaração de contratos (e outras declarações de alto nível)
|
||||
// Evite espaços estranhos entre parênteses
|
||||
// Pode omitir chaves curly para uma declaração de linha(if, for, etc)
|
||||
// else deve ser colocado na própria linha
|
||||
|
||||
|
||||
// 14. COMENTÁRIOS NATSPEC
|
||||
// usado para documentação, comentários e UIs externos
|
||||
|
||||
// Contrato natspec - sempre acima da definição do contrato
|
||||
/// @title Título do Contrato
|
||||
/// @author Nome do autor
|
||||
|
||||
// Função natspec
|
||||
/// @notice informações sobre o que funciona; mostrado quando a função é executada
|
||||
/// @dev Documentação de função para desenvolvedor
|
||||
|
||||
// Parâmetro de função / valor de retorno natspec
|
||||
/// @param algumParametro Alguma descrição do que o parametro faz
|
||||
/// @return Descrição do valor de retorno
|
||||
```
|
||||
|
||||
## Recursos adicionais
|
||||
- [Documetanção Solidity](https://solidity.readthedocs.org/en/latest/)
|
||||
- [Guia de Estilo do Solidity](https://ethereum.github.io/solidity//docs/style-guide/):
|
||||
O guia de estilo Ethereum é derivado do guia de estilo do Python [pep8](https://www.python.org/dev/peps/pep-0008/).
|
||||
- [Editor de Browser Solidity](http://chriseth.github.io/browser-solidity/)
|
||||
- [Gitter Solidity Chat room](https://gitter.im/ethereum/solidity)
|
||||
- [Estratégias de projeto modular para contratos Ethereum](https://docs.erisindustries.com/tutorials/solidity/)
|
||||
|
||||
## Contratos de Exemplo
|
||||
- [Dapp Bin](https://github.com/ethereum/dapp-bin)
|
||||
- [Solidity Baby Step Contracts](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts)
|
||||
- [ConsenSys Contracts](https://github.com/ConsenSys/dapp-store-contracts)
|
||||
- [State of Dapps](http://dapps.ethercasts.com/)
|
||||
|
||||
## Segurança
|
||||
- [Thinking About Smart Contract Security](https://blog.ethereum.org/2016/06/19/thinking-smart-contract-security/)
|
||||
- [Smart Contract Security](https://blog.ethereum.org/2016/06/10/smart-contract-security/)
|
||||
- [Hacking Distributed Blog](http://hackingdistributed.com/)
|
||||
|
||||
## Informação excluída intencionalmente
|
||||
- Libraries
|
||||
|
||||
## Estilo
|
||||
- [PEP8](https://www.python.org/dev/peps/pep-0008/) é usado como guia de estilo,
|
||||
incluindo sua filosofia geral
|
||||
|
||||
## Editores
|
||||
- [Vim Solidity](https://github.com/tomlion/vim-solidity)
|
||||
- Snippets de Editores ([Ultisnips format](https://gist.github.com/nemild/98343ce6b16b747788bc))
|
||||
|
||||
## Trabalhos Futuros
|
||||
- Novas palavras-chave: protected, inheritable
|
||||
- Lista de padrões de design comuns (throttling, RNG, atualização de versão)
|
||||
- Padrões anti-segurança comuns
|
||||
|
||||
|
||||
Sinta-se a vontade para enviar um pull request com quaisquer edições - ou email
|
||||
para nemild - / at- / gmail
|
Loading…
Reference in New Issue
Block a user