Browse Source

library update (1770129) on Fri Jul 9 04:56:51 PM CEST 2021

master
Aaron J. Milius 3 years ago
committed by Brooke L. Rediker
parent
commit
cf075fc8ed
  1. 0
      CAStore/genesis.yml
  2. 16
      CAStore/nullblock.yml
  3. 69
      README.md
  4. 66
      bin/signtx.pl
  5. 21
      config.yml
  6. 31
      docs/index.md
  7. 11
      docs/notes.md
  8. 43
      docs/pow.js
  9. 88
      docs/pow.md
  10. 2
      lib
  11. 6
      nodes/cloneit.sh
  12. 2
      salts/Genesis.yml
  13. BIN
      secrets/keys.yml
  14. 42
      t/createtx.t
  15. 6
      t/genesis.t
  16. 8
      t/hashcash.t
  17. 3
      t/merkleroot.t
  18. 6
      txpool/txcoin.yml
  19. 2
      txpool/txgen.yml

0
genesis.yml → CAStore/genesis.yml

16
CAStore/nullblock.yml

@ -0,0 +1,16 @@
--- # null block
ver: 0
data:
seq: -1
payload: ~
comment: "This is not a block (null block)"
meta:
seed: 0xb3560762
salt: 12131054599640746025 # used in address computation
salt: ~ # used in address computation
txroot: ~
audit:
peerid: Anonymous
tics: 0
ip: 0.0.0.0
prev: ~

69
README.md

@ -1,27 +1,51 @@
---
layout: simple
---
## A toy chain
The chain should have these properties:
### The chain should have these properties:
- Running on at least 2 pre-defined nodes (IP addresses given in a config file / no additional discovery necessary)-
- PoW, with every node a miner-
- The difficulty is fixed (i.e., block time is not), each block rewards 100 coins-
- ECDSA cryptography; addresses may be pure public keys-
- Protect against double spending
- Transactions can have additional data payload, signed by the sender (and there needs to be a way to set it)
- Running on at least 2 pre-defined [nodes][7] (IP addresses given in a [config file][8] / no additional discovery necessary)-
- [PoW][9], with every node a miner-
- The [difficulty][10] is fixed (i.e., block time is not), each [block rewards][12] 100 coins-
- [ECDSA][13] cryptography; addresses may be pure public keys-
- Protect against [double][14] spending
- [Transactions][11] can have additional data payload, signed by the sender (and there needs to be a way to [set it][5])
- Blocks can have additional data payload (and there needs to be a way to set it)
- Implement a simple REST-like web service API which implements the following services and returns JSON data:
* Query the block count.
* Query a single block and return all its transaction data.
* Query a single transaction and return all its data.
* Create a transaction from JSON data and accept it for mining
- Implement a simple REST-like [web service API][1] which implements the following services and returns JSON data:
* Query the [block count][2].
* Query a [single block][3] and return all its transaction data.
* Query a [single transaction][4] and return all its data.
* [Create a transaction][5] from JSON data and accept it for [mining].
### Example of curl commands
```sh
# getting block count
curl http://127.0.0.1:8089/api/0.0/getheight
# getting 4th block
curl http://127.0.0.1:8089/api/0.0/getblock?n=4
# getting transaction Ztxrms5c5oKqb9Zof3xeC5Q2ZQjSaWv7FU4rAxe2s3sP
curl http://127.0.0.1:8089/api/0.0/gettx?txaddr=Ztxrms5c5oKqb9Zof3xeC5Q2ZQjSaWv7FU4rAxe2s3sP
# posting a transaction
cat txpool/tx.yml | sed -e "s/$/%0a/g" | curl -s -X POST http://127.0.0.1:8089/api/0.0/settx -d @-
# processing the txpool (mining)
curl http://127.0.0.1:8089/api/0.0/minepool
```
### Security Warning
Blockchain are transparent and public so we encrypt private keys and other sensitive data,
however as it is just a toy, we expose **all the files** for educational purpose.
>> ** PLEASE DO NOT USE IN A PRODUCTION ENVIRONMENT **
note:
sensitive data are encrypted w/ git-crypt;
please send your public key if you need access
please send us your public key if you need access
or ask for a shared DH secret
decrypt can be done with the command :
```sh
@ -30,3 +54,20 @@ The chain should have these properties:
#gpg --decrypt local.key.asc | git-crypt unlock -
```
[1]: webservice.html
[2]: http://127.0.0.1:8089/api/0.0/getheight
[3]: http://127.0.0.1:8089/api/0.0/getblock
[4]: http://127.0.0.1:8089/api/0.0/gettx
[5]: http://127.0.0.1:8089/api/0.0/settx
[6]: http://127.0.0.1:8089/api/0.0/minepool
[7]: http://127.0.0.1:8089/api/0.0/getnodes
[8]: http://127.0.0.1:8089/api/0.0/config
[9]: http://127.0.0.1:8089/docs/pow.html
[10]: http://127.0.0.1:8089/docs/difficulties.html
[11]: http://127.0.0.1:8089/api/transacion.html
[12]: http://127.0.0.1:8089/docs/bkreward.html
[13]: http://127.0.0.1:8089/admin/keygen.html
[14]: http://127.0.0.1:8089/docs/UTXO.html

66
bin/signtx.pl

@ -3,19 +3,17 @@
BEGIN { if (-e $ENV{SITE}.'/lib') { use lib $ENV{SITE}.'/lib'; } }
use config;
use config qw(loadYaml $config);
use essential qw(sdate version);
use misc qw(khash yamlify);
use TXPOOL qw(saveTxPool);
use TXPOOL qw(saveTxPool txdigest);
use CAStore qw(CASWrite);
use ECKeys qw(ecsign ecverif getPeerid loadKeys);
use YAML::Syck qw(LoadFile Dump DumpFile);
my $keys = loadKeys();
foreach my $id (keys %{$keys}) {
my $pub = $keys->{$id}{public};
$keys->{$pub}{id} = $id;
}
my $keys = loadKeys($ENV{SITE}.'/secrets/keys.yml');
our $aliases = &loadYaml($ENV{SITE}.'/secrets/aliases.yml');
my $keyfile = $ENV{SITE}.'/secrets/coinbase.yml';
if (-e $keyfile) {
my $local_keys = &loadKeys($keyfile);
@ -25,42 +23,51 @@ if (-e $keyfile) {
$keys->{coinbase} = $local_keys->{coinbase};
}
}
foreach my $id (keys %{$keys}) { # list all known aliases ...
my $pub = $keys->{$id}{public};
$aliases->{$pub} = $id if (! defined $aliases->{$pub});
printf " - %-13s: %-46s (%-36s);",$id,$pub,$keys->{$id}{name};
printf " bot:%s\n", &botname::botname($pub);
}
printf "--- keys %s...\n",Dump($keys);
#printf "--- aliases %s...\n",Dump($aliases);
my $txf = shift;
my $tx = LoadFile($txf);
my $date = (exists $tx->{timestamp})? &sdate($tx->{timestamp}) : &sdate(time);
my $tx = LoadFile($txf);
my %signatures = ();
my %delta = ();
foreach my $sign (@{$tx->{signatures}}) {
my ($pub) = keys %{$sign};
$signatures{$pub} = $sign->{$pub}[0];
$signatures{$pub} = $sign->{$pub};
$delta{$pub} = 0;
}
printf "--- signatures %s...\n",Dump(\%signatures);
foreach my $in (@{$tx->{inputs}}) {
my ($pub) = keys %{$in};
my $id = (exists $keys->{$pub}{id}) ? $keys->{$pub}{id} : $pub;
$pub = $keys->{$id}{public} if (exists $keys->{$id}{public});
my $id = (exists $aliases->{$pub}) ? $aliases->{$pub} : $pub;
my $key58 = (exists $keys->{$id}) ? $keys->{$id}{public} : $pub;
my $value = $in->{$pub};
$valuein += $value;
$delta{$pub} -= $value;
printf "in: %s from %s (%s)\n",$pub,$id;
printf "in: %s from %s (%s)\n",$value,$id,$key58;
}
foreach my $out (@{$tx->{outputs}}) {
my ($pub) = keys %{$out};
my $id = (exists $keys->{$pub}{id}) ? $keys->{$pub}{id} : $pub;
$pub = $keys->{$id}{public} if (exists $keys->{$id}{public});
my $id = (exists $aliases->{$pub}) ? $aliases->{$pub} : $pub;
my $key58 = (exists $keys->{$id}) ? $keys->{$id}{public} : $pub;
my $value = $out->{$pub};
$valueout += $value;
$delta{$pub} += $value;
printf "out: %s to %s (%s)\n",$value,$pub,$id;
printf "out: %s to %s (%s)\n",$value,$id,$key58;
}
if ($valuein != $valueout) {
printf "error: i:%s != o:%s\n",$valuein,$valueout;
if ($valuein < $valueout) {
printf "error: i:%s < o:%s\n",$valuein,$valueout;
}
my $txi = {
timestamp => $tx->{timestamp},
@ -84,33 +91,36 @@ my $txio = {
foreach my $pub (keys %delta) {
my $value = -$delta{$pub};
my $id = (exists $aliases->{$pub}) ? $aliases->{$pub} : $pub;
if (exists $signatures{$pub}) {
my $id = (exists $keys->{$pub}{id}) ? $keys->{$pub}{id} : $pub;
my $key58 = (exists $keys->{$id}{public}) ? $keys->{$id}{public} : $pub;
my $key58 = (exists $keys->{$id}) ? $keys->{$id}{public} : $pub;
my $msg;
if ($value > 0) { # input
$msg = qq'["$pub","$value","$tx->{message}"]';
$msg = sprintf q'[%s,%s,%s]',$pub,$value,&txdigest($txihash);
} elsif ($value == 0) {
$msg = sprintf q'[%s,%s,%s]',$pub,$value,&txdigest($txiohash);
} else { # output
$msg = qq'["$id","$value","$tx->{txohash}"]';
$msg = sprintf q'[%s,%s,%s]',$pub,$value,&txdigest($txohash);
}
printf "msg: %s\n",$msg;
if (defined $signatures{$pub}) {
printf "signatures.%s: %s\n",$pub, join',',@{signatures{$pub}};
my $sig = $signatures{$pub}[0];
my $sigok = &ecverif($key58,$sig,$msg);
printf "signature for %s (%s) ? %s\n",$id,$key58,($sigok)?'ok':'invalid';
if (! $sigok) {
my $sig = &ecsign($id,$msg);
my $sig = &ecsign($id,$msg);
printf "sig: %s: %s (corrected)\n",$id,$sig;
$signatures{$pub} = [ $sig, $date ];
$signatures{$pub} = [ $sig, $date, $msg ];
}
} else {
my $id = (exists $keys->{$pub}{id}) ? $keys->{$pub}{id} : $pub;
my $id = (exists $aliases->{$pub}) ? $aliases->{$pub} : $pub;
if (exists $keys->{$id}{private}) {
my $sig = &ecsign($id,$msg);
printf "sig: %s: %s\n",$id,$sig;
$signatures{$pub} = [ $sig, $date ];
my $sig = &ecsign($id,$msg);
printf "sig: %s: %s\n",$id,$sig;
$signatures{$pub} = [ $sig, $date, $msg ];
} else {
printf "sig: don't have private key for %s\n",$id;
printf "sig: don't have private key for %s\n",$id;
}
}
}

21
config.yml

@ -1,12 +1,13 @@
--- # toychain's config
version: 1.06
version: 1.12
chain: toychain
apiver: '0.0'
ipfsgw: 8390
port: 8089
# p2p network = api+1
apis:
# p2p network
# api = p2p+1
nodes:
- 127.0.0.1:8091
- 127.0.0.2:8093
- 127.0.0.3:8095
@ -16,11 +17,25 @@ apis:
# block parameters :
bkver: 0
bkreward: 100
coinbase:
reward: 50
public: ZPD9SRTr5ZMx6coZV6NrUxgmVfCkqB55gTdAwJKQVjp7W
signature: ~
genhash: Z9BEepHz9jLWzNebDEZTrEKusuU9zomFoaaPxngCQ5D39
genhash: Z9BEdvJt9F2xeY6BP3gXMvGikFvcUv1kvESQyhSKznLDi
genhash: Z9BEeytxKdWLtGhirNstvvRtJ4273GmVqJ7r2pKmoCR7G
genhash: Z9BEdXmPNa1DkEJKQ1BhuMg7M1nHRD6NLKoXpJ6X84NqK
nullhash: Z9BEeWD4Mww7yrXyPRXrfM2y6FxsQGfaNPzC8DxWq4ATq
txgen: Ztxrms5c5oKqb9Zof3xeC5Q2ZQjSaWv7FU4rAxe2s3sP
txgen: ZTxoBj3SNdKGMxXLTdxScnmScN7uCveoM2zPmDoMS4CN
txgen: ZTxGeH4J9oWMci2pcJ7yZ1baMb47i7zd6ihHissKifvQ
txcoin: ZCBuCkQFRBeiGnANEwb65TZptSTUpm62WYS4Xj9gkMLU
txcoin: ZCBtx9SS9n57R2cx3AAuRDKJ4b9WsWA5MoTVEtxGQAdV
txcoin: ZCBtx7Wg59hvMogWDchKVcGUMo68qDe2dkRfzaskAh3G
# Proof of Work option

31
docs/index.md

@ -0,0 +1,31 @@
---
layout: simple
---
# Toy Chain ...
- [settings][6]
- [explorer][2]
- [web-service][7]
### documentation
- [README][3]
- [genesis][8]
- [transactions][9]
- [API][1]
- [notes][5]
### Installation
- [INSTALL.md][4]
[1]: /api/
[2]: /docs/explorer.html
[3]: /README.html
[4]: /INSTALL.md
[5]: /docs/notes.html
[6]: /admin/settings.html
[7]: /webservice.html
[8]: /docs/genesis.html
[9]: /docs/transactions.html

11
notes.md → docs/notes.md

@ -1,3 +1,7 @@
---
layout: simple
base: '../'
---
# Design Notes
@ -48,5 +52,10 @@
- PoW can be replaced by ZK proof of some Work
- should it be txo which carries the burden of proof of work ?
- validator already do a great job making the system "alive" that's already work !
- validator already do a great job making the system "alive"
- block reward could be proportional to the number of tx in the block i.e. the "real" work is indeed the verif not a hash-puzzle
- How to mitigate DDoS on Mempool ?
-
- why would we want making block more and more difficult to add when technology advance ???
(how to make spice of spamming constant through technology ?)

43
docs/pow.js

@ -0,0 +1,43 @@
const useCapture = true; // capture, bubbling: false
button = document.getElementsByTagName('button')[0];
button.addEventListener('click',hashcash,false);
button.addEventListener('submit',hashcash,false);
console.log(button)
function hashcash(ev) {
console.log('hashcash.ev: %o',ev);
let algo = document.getElementsByName('algo')[0].value;
let data = document.getElementsByName('data')[0].value;
let nonce = document.getElementsByName('nonce')[0].value || '12131054600136590020';
let dif = document.getElementsByName('dif')[0].value;
let url = api_url + `hashcash?a=${algo}&b=${data}&n=${nonce}&d=${dif}`
document.getElementById('pow').innerText = 'no-proof';
let promised = fetch(url).
then(resp => resp.json()).
then(obj => {
console.log('pow.hashcash.obj:',obj);
document.getElementsByName('hashcash')[0].innerText = '0x'+obj.hash;
document.getElementsId('pow').innerText = obj.pow;
}).
catch(console.error);
}
let url = api_url + 'config';
let promised = fetch(url).
then(resp => resp.json()).
then(obj => {
console.log('pow.obj.config:',obj.config);
let dif = obj.config.difficulty
console.log('pow.dif:',dif);
let elem = document.getElementById('dif');
elem.innerText = dif;
//let buf = elem.innerHTML; buf = buf.replace(':dif',dif); elem.innerHTML = buf;
elem = document.getElementsByName('dif')[0];
elem.value = dif;
return obj.config
}).
catch(console.error)

88
docs/pow.md

@ -0,0 +1,88 @@
---
layout: simple
---
# Proof of Work
We use a [hashcash][1] type of proof of work (see also [Adam Back][ab] annonce)
where the difficulities is set to <span id=dif><i>:dif</i></span>.
hash algo: <input name="algo" value="SHA256" size="7">
<br>data: <input name="data" value="some data" size=24>
<!-- perl -Ilib -Mmisc -e 'print $misc::inonce'
5: 12131054599640746025
6: 12131054600136000000
8: 12131054604672000000
-->
<br>nonce: <input name="nonce" value="12131054604672000000" size=20>
<br>difficulty: <input name="dif" value="7" size="2">
<br>hashcash: <span name="hashcash"><i>?</i></span>
<br>proof: <span id="pow"><i>:pow</i></span>
<button>compute</button>
---
## note:
- perl hashcash : [/lib/Chain.pm#hashcash](/lib/Chain.pm#hashcash)
- original hashcash's [gi(s)t]: &lt;[gist:8748be59087e244f916618ac2d66ae3b][hologit]> (SHA1 based)
### code
```perl
# -----------------------------------------------------
sub hashcash { # ex: hashcash('SHA256',$data,$nonce,7);
my $alg = shift;
my $difficulty = pop; # difficulty < 8
my $nonce = pop; # 64 bits of nonce
my $n = $nonce;
printf "hashcash.nonce: %s\n",$nonce;
printf "hashcash.difficulty: %s\n",$difficulty;
#printf "data: %s\n",join'',@_;
my $l = 0;
my $match = '8'.substr('0'x$difficulty,0,$l); # set the MSB to 1 to avoid padding problems
my $iv;
use Crypt::Digest qw();
my $msg = Crypt::Digest->new($alg) or die $!;
$msg->add(join'',@_);
#printf "iv: %s\n",$msg->hexdigest();
my $h16;
my $pn = pack'Q',$nonce; # Quad
while (1) { # length($pn) < $difficulty) {
$iv = $msg->clone;
$iv->add($pn);
$h16 = $iv->hexdigest();
if (substr($h16,0,$l+1) eq $match) {
my $elapse = time - $^T + 1;
if ($0 =~ m/\.t$/) { $elapse = 3; }
my $rate = ($n - $nonce) / $elapse / 1000;
#printf "%d: %s %s %s %.0fkH/s %.1fmin\n",$l, $n,unpack('H*',$pn),$h16,$rate,$elapse/60;
# count any zeros : ($h16 =~ m/0/g) !
my $zc = ($h16 =~ /80+/) ? length($&) : 0;
#print "zc: $zc\n";
$l = $zc;
last if $zc >= $difficulty;
$match = '8'.substr('0'x$l,0,$l);
#} else {
# printf "%d: %s %s %s %s\r",$l, $n,unpack('H*',$pn),$h16,$match;
}
$pn = pack('Q',$n++);
}
return pack('H*',$h16),$n-1;
}
# -----------------------------------------------------
```
[1]: http://www.hashcash.org/papers/hashcash.pdf
[ab]: http://www.hashcash.org/papers/announce.txt
[2]: https://www.cs.jhu.edu/~rdas/finalreport.pdf
[3]: https://www.arijuels.com/wp-content/uploads/2013/09/JB99.pdf
[4]: http://pubs.sciepub.com/jcsa/5/2/2/index.html
[4d]: http://www.sciepub.com/portal/downloads?doi=10.12691/jcsa-5-2-2&filename=jcsa-5-2-2.pdf
[hologit]: https://hologit-ml.ipns.cf-ipfs.com/cbuquo/hashcash.git
[gist]: git@gist.github.com:8748be59087e244f916618ac2d66ae3b.git
<script src="pow.js"></script>

2
lib

@ -1 +1 @@
Subproject commit 8a8f4a627abf429965d7d9db4ff519e83f57945c
Subproject commit d4bea95cde2025454813231b121ffffa846eee0a

6
nodes/cloneit.sh

@ -5,7 +5,11 @@ while [ -e "node$i" ]; do
i=$(expr $i + 1)
done
echo create node$i
#git clone --recursive git@git.toptal.com:screening/Michel-Combes node$i
if [ -d ../lib ]; then
git clone --recursive ../.git node$i
else
git clone --recursive git@git.toptal.com:screening/Michel-Combes node$i
fi
port=$(expr 8089 + 2 \* $i )
echo "node$i: port=$port"
rm node$i/config.yml

2
salts/Genesis.yml

@ -1 +1 @@
salt: 8163726776976957032
salt: 8163726777753892901

BIN
secrets/keys.yml

42
t/createtx.t

@ -0,0 +1,42 @@
#
BEGIN { if (-e $ENV{SITE}.'/lib') { use lib $ENV{SITE}.'/lib'; } }
use TXPOOL qw($TXPOOL $UTXO createTx isTxValid addTxPool);
use CAStore qw(CASRead);
use YAML::Syck qw(Dump);
printf "--- keys %s...\n",Dump($ECKeys::keys);
printf "--- aliases %s...\n",Dump($ECKeys::aliases);
$UTXO->{$ECKeys::keys->{faucet}{public}} = 1;
printf "--- UTXO %s...\n",Dump($UTXO);
my $tx = {
message => 'this is a test transaction',
inputs => [ { 'faucet' => 1 } ],
outputs => [ { 'self' => 1 } ]
};
my ($txaddr,$tx) = &createTx($tx,'txpool');
printf "txaddr: %s\n",$txaddr;
my $txok = &isTxValid($tx);
printf "is %s valid: ? %s\n",$txaddr,$txok;
if ($txok) {
&addTxPool($txaddr);
}
print "TxPool:\n";
for my $i (0 .. $#$TXPOOL) {
printf " %d. %s\n",$i,$TXPOOL->[$i];
}
print ".]n";
#my $txp = &CASRead($ENV{SITE}.'/txpool',$txaddr);
#printf "--- txp %s...\n",Dump($txp);
exit $?;
1;

6
t/genesis.t

@ -9,9 +9,9 @@ use DAG qw(DAGRead);
my $genblock = $Genesis::genblock;
my $genhash = $Genesis::genhash;
my $genaddr = $gendblock->{bkaddr};
printf "genhash%s\n",$genhash;
printf "genaddr%s\n",$genaddr;
my $genaddr = $genblock->{bkaddr};
printf "genhash: %s\n",$genhash;
printf "genaddr: %s\n",$genaddr;
my $genbk = &DAGRead('blocks',$genhash);
#printf "--- blk %s...\n",Dump($blk);

8
t/hashcash.t

@ -25,9 +25,13 @@ printf "// testing $0\n";
my $n0 = rand64(); # n < 18446744073709551616
printf "n0:%s\n",$n0;
#my ($hc,$n) = &hashcash('SHA256','some data',12131054599640746025,6);
#my ($hc,$n) = &hashcash('SHA256','some data',12131054600136590019,8);
my ($hc,$n) = &hashcash('SHA256','some data',12131054604673102375,9);
printf "hc: %s %s %s\n",unpack('H*',$hc),$n,unpack'H*',pack('Q',$n);
my ($hc,$n) = &hashcash('SHA256','hello world',$n0,5);
printf "hc: %s %x %s\n",unpack('H*',$hc),$n,unpack'H*',pack('Q',$n);
#($hc,$n) = &hashcash('SHA256','hello world',$n0,5);
#printf "hc: %s %x %s\n",unpack('H*',$hc),$n,unpack'H*',pack('Q',$n);
#my ($hc,$n) = &hashcash('SHA256','hello world',$n0,'abcdef');
#printf "hc: %s %x %s\n",unpack('H*',$hc),$n,unpack'H*',pack('Q',$n);

3
t/merkleroot.t

@ -3,8 +3,9 @@
BEGIN { if (-e $ENV{SITE}.'/lib') { use lib $ENV{SITE}.'/lib'; } }
use TXPOOL qw(computeMerkleRoot mbase16);
$TXPOOL::dbug = 1;
my $a = [qw(a b c d e f g)];
my $a = [map { 'Z'.$_; } qw(a b c d e f g)];
my $mr = &computeMerkleRoot($a);

6
txpool/txcoin.yml

@ -1,11 +1,11 @@
---
timestamp: '1625385951347499858'
message: This is a coinbase transaction of 100 coins to be distributed to Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq
inputs:
- coinbase: 100
nonce: '3976914969180171529'
outputs:
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 100
message: This is a coinbase transaction of 100 coins to be distributed to Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq
timestamp: '1625385951347499858'
nonce: '3976914969180171529'
pow: '3976914969180292365'
signatures:
- coinbase: ~

2
txpool/txgen.yml

@ -5,7 +5,7 @@ inputs:
nonce: '3976914969180171529'
outputs:
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 50
payload: This is a coinbase transaction of 50 coins for the genesis block
message: This is a coinbase transaction of 50 coins for the genesis block
pow: '3976914969180292365'
signatures:
- coinbase: Zan1RjVTw7GPVyd7aygjWSrGCtX3M8CVRu3NAyqLC8MToNPE93ju4RrFFjunnbeTYnudR2gSKCamK82xjEfWEtGzGvTRDw25MG
Loading…
Cancel
Save