Bitcoin Exs PDF
Bitcoin Exs PDF
Bitcoin Exs PDF
25.2.2017
1 Introducción
Buscando en Internet se pueden encontrar muchos ejemplos para programar aplicaciones que
hagan uso de las tecnologías bitcoin y blockchain.
Esta nota solamente busca concretar algunos ejemplos sencillos usando la librería bitcoinj, un
entorno de desarrollo para java.
https://bitcoinj.github.io/
es incompleta
tiene bugs
la documentación no siempre está al día
cambia con cierta frecuencia (desarrollo activo)
por lo que los programas que se presentan puede que haya que afinarlos.
2 Contexto
Todos los ejemplos están parametrizados para trabajar sobre la red oficial de bitcoin (manejando
monedas convertibles a euros)
NetworkParameters netParams = MainNetParams.get();
https://blockchain.info/
http://tbtc.blockr.io/
3 Logging
Para ver trazas de qué está haciendo la aplicación, hay que activar un logger.
https://www.slf4j.org/
lo descomprimimos
./slf4j-1.7.22/slf4j-1.7.22/slf4j-simple-1.7.22.jar
4 Claves y direcciones
El primer programa crea una clave aleatoria e imprime sus partes pública, privada y su dirección
en la red bitcoin:
System.out.println("key:");
System.out.println(" pub: " + key.getPublicKeyAsHex());
System.out.println(" sec: " + key.getPrivateKeyAsHex());
System.out.println(" address: " + key.toAddress(netParams));
}
4.1 Ejercicio
Se propone crear una dirección de vanidoso (vanity address). Ver
https://en.wikipedia.org/wiki/Vanity_plate
Concretamente, elija 4 letras (por ejemplo, “pepe”) y cree una dirección que empiece así
1pepe…
ej. 1pepe9NvM1cWYweJSPt62cJuc19h29Tb3R
Debido a la irreversibilidad de las funciones hash, no hay más remedio que ir generando y
probando claves hasta obtener una que cumpla el patrón deseado.
Ver discusión en
https://en.bitcoin.it/wiki/Vanitygen
5 Wallet
Un programa útil puede ser el que muestra una cartera, almacenada en un fichero, creándola si es
la primera vez:
Coin System.out.println(coin.toFriendlyString())
coin = Coin.parseCoin("0.1")); 0.10 BTC
coin = Coin.valueOf(0, 1)); 0.01 BTC
coin = Coin.valueOf(1000) 0.00001 BTC
Cuando el escenario no es tan simple, hay que trabajar la transacción concreta. El siguiente
ejemplo hace lo mismo preparando explícitamente la salida de la transacción:
void send(NetworkParameters netParams,
String prefix, Coin coin1, Address address)
throws InsufficientMoneyException, ExecutionException,
InterruptedException {
WalletAppKit kit = new WalletAppKit(netParams, new File("."), prefix);
kit.startAsync();
kit.awaitRunning();
6.1 Ejercicio
Dada una cantidad de monedas X, repártala en N partes y envíe una parte a cada destinatario de
una lista de N direcciones. Hay que hacer una única transacción para acotar las comisiones
pagadas a los mineros.
7 Firmas N de M
Se trata de hacer una transacción que involucra a M partes y solamente puede ser cobrada cuando
N receptores están de acuerdo en quién debe cobrarla.
Por ejemplo, una firma 2 de 3. Una dirección A genera una transacción para 3 partes, B1, B2 y B3.
Para que C pueda cobrarla, necesita las firmas de 2 elementos del conjunto {B1, B2, B3}.
En este caso hay que trabajar con claves públicas, no nos basta tener direcciones. A partir de las
claves públicas en hexadecimal, podemos obtener la codificación en bytes:
0 <sig1> <sig2>
Ver https://en.bitcoin.it/wiki/Transaction
Es importante destacar que el orden de las firmas <sig_i> debe respetar el orden de las claves públicas
<pubKey_i>.
7.1 Transacciones
El que paga genera una transacción T1, firmada por él.
Necesitamos una transacción intermedia T2, firmada por 2, para que el dinero llegue al destino
final F.
7.2 Generación de T1
Hay que ajustar el script de la transacción para que sea del tipo multifirma: se requerirán N firmas
de una lista de claves:
Es importante apuntarse la transacción porque habrá que mandársela a los posibles signatarios
para que la firmen. También suele ser útil apuntarse su hash para poder seguirla en la blockchain.
Transaction T1 = sendNM(...);
String T1Hash = T1.getHashAsString();
System.out.println("T1: " + T1Hash);
saveToFile(T1);
input2.verify(output1);
WalletAppKit kit = …
PeerGroup peerGroup = kit.peerGroup();
ListenableFuture<Transaction> future = peerGroup.broadcastTransaction(T2).future();
future.get();
La transacción entrante la podemos recuperar del fichero que generamos en la sección previa
Y hay que seleccionar, de todas las salidas de la transacción, la que nos interesa para multi-firma
Transaction T1 = …
TransactionOutput output1 = getMultiSigOutput(T1);
Script scriptPubKey1 = output1.getScriptPubKey();
List<ECKey> pubKeyList = scriptPubKey1.getPubKeys();
De esas claves, tendremos acceso a alguna clave privada que nos permita firmar. Sabiendo la clave
privada, se firma
ECKey key = …
Transaction.SigHash type = Transaction.SigHash.ALL;
Sha256Hash sighash = T2.hashForSignature(0, scriptPubKey1, type, false);
ECKey.ECDSASignature ecdsaSignature = key.sign(sighash);
Para encontrar la clave de firma, hay que buscar en la wallet. Este código cada uno se lo organiza a
su manera, siendo la forma de operar como sigue:
WalletAppKit kit =
new WalletAppKit(netParams, new File(DIRECTORY), PREFIX);
kit.startAsync();
kit.awaitRunning();
Wallet wallet = kit.wallet();
byte[] pubKeyBytes = Utils.parseAsHexOrBase58(PUBKEYHEX);
ECKey key = wallet.findKeyFromPubKey(pubKeyBytes);
7.5 Cierre
Cuando ya tenemos suficientes firmas, bien generadas por nosotros mismos, bien recibidas de un
signatario, nos quedamos con la N que hacen falta y generamos la transacción final para que el
destinatario reciba el dinero
Script inputScript =
ScriptBuilder.createMultiSigInputScript(signatureList);
input2.setScriptSig(inputScript);
input2.verify(output1);
7.6 Ejercicio
Aplique el código anterior a un contrato de compra-venta supervisado por un tercero. Es decir, es
un escenario que requiere la firma de 2 de 3.
C es el cliente
V es el vendedor
J es el juez
Si piensa que C tiene razón, firma la transacción para C y se la pasa a C para que firme y
recupere su dinero.
Si piensa que V tiene razón, firma la transacción para V y se la pasa a V para que firme y
cobre su producto.
7.7 Ejemplo
Generamos una transacción T1 para que firmen 2 de 3:
hash: f7d8b240f28fd012bcb2d42912a2767136944f9ec0a15aabfd4bae4f4221b039
output 0
value: 0.0250877 BTC
scriptPubKey:
DUP
HASH160
PUSHDATA(20)[fcc7cb46725e438d2c4f2689d84865f071d373bc]
EQUALVERIFY
CHECKSIG
output 1
value: 0.0123 BTC
scriptPubKey:
2
PUSHDATA(33)[0328b759cb1775dd3465c5ac925999e5ed2ed9886acbac88cc8ba82ae8b
b59d48c]
PUSHDATA(33)[02b4a45b26cd6e101283270e247875afeb71593754e0eb1dd9cc109c40a
c395dd2]
PUSHDATA(33)[03258f48893c359d0f573e8ece07dee26e4afdccbf42eee61c67f802d58e
d2e597]
3 CHECKMULTISIG
hash: 1b13a553ab4f656fe3629b6012e6309b160622dc72f19a8e12849df475a9c56c
output 0
value: 0.0122 BTC
scriptPubKey:
DUP
HASH160
PUSHDATA(20)[bded386a1395fa69d531719a470c43408851f926]
EQUALVERIFY
CHECKSIG
La primera, T1 (f7d8b240f28fd012bcb2d42912a2767136944f9ec0a15aabfd4bae4f4221b039):
… y la segunda: T2 (7890353f52404fee2fb55c0ac4a6f220ce76452b4bf2b047ad8ebf8ce5c8d4d4):
8 Métodos auxiliares para intercambiar transacciones y firmas
8.1 Transacciones
8.2 Firmas