Aaron J. Milius
4 years ago
committed by
Brooke L. Rediker
90 changed files with 1779 additions and 179 deletions
-
1.gitattributes
-
15CAStore/genesis.yml
-
16CAStore/nullblock.yml
-
15README.md
-
18admin/config.md
-
21admin/index.md
-
18admin/keygen.js
-
22admin/keygen.md
-
19admin/manual-registration.md
-
27admin/new-settings.md
-
47admin/register.js
-
21admin/register.md
-
19admin/settings.md
-
15api/audit.md
-
15api/cmd.md
-
22api/config.md
-
16api/env.md
-
16api/explore.md
-
22api/getblock.js
-
24api/getblock.md
-
51api/index.md
-
45api/nodes.js
-
31api/nodes.md
-
20api/peerid.js
-
15api/peerid.md
-
53api/transaction.js
-
43api/transaction.md
-
4bin/apirun
-
16bin/signtx.pl
-
5bin/yml2json.sh
-
34config.yml
-
23config0.yml
-
21curltest.sh
-
10docs/UTXO.md
-
111docs/block.js
-
39docs/block.md
-
30docs/chain.js
-
22docs/chain.md
-
23docs/difficulties.md
-
27docs/explorer.md
-
57docs/genesis.js
-
27docs/genesis.md
-
74docs/heads.js
-
23docs/heads.md
-
5docs/index.md
-
44docs/info.js
-
29docs/info.md
-
30docs/minepool.js
-
30docs/minepool.md
-
24docs/mining.md
-
30docs/nodes.js
-
21docs/nodes.md
-
22docs/notes.md
-
4docs/pow.js
-
27docs/status.md
-
30docs/test.js
-
42docs/test.md
-
51docs/transactions.js
-
46docs/transactions.md
-
28docs/txpool.js
-
21docs/txpool.md
-
32eckeygen.pl
-
2lib
-
10nodes/cloneit.sh
-
2salts/Genesis.yml
-
BINsecrets/keys.yml
-
BINsecrets/nicknames.yml
-
11t/blockaddr.t
-
6t/createtx.t
-
BINt/eckeys.t
-
2t/genesis.t
-
3t/hashcash.t
-
7templ/config.yml
-
1templ/genesis.yml
-
14templ/runtest.sh
-
17templ/runtime.yml
-
1templ/salt.yml
-
20templ/tx.yml
-
1templ/tx02.json
-
23templ/tx02.yml
-
35templ/tx03.json
-
17templ/txcb01.yml
-
17templ/txcoin.yml.sig
-
6templ/txexample.yml
-
3templ/txgen.yml
-
2templ/txnull.yml
-
19templ/txudj.yml
-
1templ/txvalid.json
-
18templ/txvalid.yml
-
11txpool/txgen.yml
@ -1,15 +0,0 @@ |
|||
--- # genesis block |
|||
ver: 0 |
|||
data: |
|||
seq: 0 |
|||
payload: /ipfs/QmWM48KvyK9YyPjJt69erxVPN3nbXVMgZWrncRJhAVkGAv |
|||
comment: "This is the genesis block" |
|||
meta: |
|||
seed: 0xb3560762 |
|||
salt: ~ # used in address computation |
|||
txroot: ~ |
|||
audit: |
|||
peerid: Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq |
|||
tics: 1623830817245864895 |
|||
ip: 83.78.4.228 |
|||
prev: ZdtrjkYsAYUeBCs4DRjtVYwPevpxvHjGT2PRauANr3Vao |
@ -1,16 +0,0 @@ |
|||
--- # 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: ~ |
@ -0,0 +1,18 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
## Config parameters |
|||
|
|||
|
|||
Important parameter to be updated: |
|||
|
|||
- genhash |
|||
- txcoin |
|||
- coinbase public key & signature |
|||
|
|||
|
|||
file : [$SITE/config.yml][1] |
|||
|
|||
|
|||
[1]: /api/v0.0/getcas?dir=.&addr=config |
|||
|
@ -0,0 +1,21 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain Admin Page |
|||
|
|||
1. [signup][1] ([keygen][1]) |
|||
1. [settings][2] |
|||
1. [README][3] |
|||
|
|||
|
|||
## Elliptic Curves Keys |
|||
|
|||
1. [EC keys][4] |
|||
1. [coinbase key][5] |
|||
|
|||
|
|||
[1]: keygen.html |
|||
[2]: settings.html |
|||
[3]: /README.html |
|||
[4]: /api/v0.0/getcas?dir=secrets&addr=keys |
|||
[5]: /api/v0.0/getcas?dir=.&addr=registration |
@ -0,0 +1,18 @@ |
|||
const useCapture = true; // capture, bubbling: false
|
|||
var elem = document.getElementsByTagName('button')[0]; |
|||
elem.addEventListener('click',keygen,useCapture); |
|||
|
|||
function keygen(ev) { |
|||
console.log('keygen: %o',ev) |
|||
let name = document.getElementsByTagName('input')[0].value; |
|||
let namep = name.replace(/ /g,'+'); |
|||
let url = api_url + `keygen?name=${namep}`; |
|||
let data = fetch(url).then(resp => resp.json()). |
|||
then(obj => { |
|||
let tarea = document.getElementsByTagName('textarea')[0]; |
|||
tarea.innerText = JSON.stringify(obj.identity); |
|||
|
|||
console.log('keygen.obj.keys:',obj.keys); |
|||
}). |
|||
catch(console.error); |
|||
} |
@ -0,0 +1,22 @@ |
|||
--- |
|||
layout: simple |
|||
base: "../" |
|||
--- |
|||
## Toy-Chain : Key pair Generation |
|||
|
|||
<input name="name" placeholder="name (optional)"><button>create</button> |
|||
|
|||
identity: |
|||
<textarea> |
|||
</textarea> |
|||
<!--<button>save</button>--> |
|||
|
|||
key files: [$SITE/secrets/keys.yml][1] |
|||
|
|||
<script src="keygen.js"></script> |
|||
|
|||
|
|||
[1]: /api/v0.0/getcas?dir=secrets&addr=keys |
|||
|
|||
|
|||
|
@ -0,0 +1,19 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# manual miner registration |
|||
|
|||
1. edit [templ/txcoin.yml][1] |
|||
{% comment %} |
|||
2. run ``signtx.pl templ/txcoin.yml`` |
|||
3. view [templ/txcoin.yml.sig][2] |
|||
4. update [registration.yml][4] |
|||
{%- endcomment -%} |
|||
3. run [t/genesis.t][3] |
|||
4. verify [registration.yml][4] |
|||
|
|||
|
|||
[1]: /api/v0.0/getyml?f=templ/txcoin.yml |
|||
[2]: /api/v0.0/getyml?f=templ/txcoin.yml.sig&encode=json |
|||
[3]: /t/genesis.t |
|||
[4]: /api/v0.0/getyml?f=registration.yml&encode=json |
@ -0,0 +1,27 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
## ToyChain Settings |
|||
|
|||
In order to have a functional blockchain you need |
|||
|
|||
1. [generate][1] a node [keypair][9] (ECDSA for signing transactions) |
|||
1. [register][2] as a miner by creating a coinbase transaction |
|||
1. create [genesis][3] block |
|||
1. update [config][10] file (and restart API) |
|||
1. connect to peers on the [network][4] |
|||
1. collect transactions from [txpool][5] and validate them |
|||
1. [minepool][6] |
|||
2. [explore][8] the [chain][7] |
|||
|
|||
[1]: /admin/keygen.html |
|||
[2]: /admin/register.html |
|||
[3]: /docs/genesis.html |
|||
[4]: /api/nodes.html |
|||
[5]: /docs/txpool.html |
|||
[6]: /api/minepool.html |
|||
[7]: /docs/chain.html |
|||
[8]: /api/explore.html |
|||
[9]: /api/v0.0/getcas?dir=secrets&addr=keys |
|||
[10]: /admin/config.html |
|||
[11]: /api/v0.0/getcas?dir=.&addr=config |
@ -0,0 +1,47 @@ |
|||
const useCapture = true; // capture, bubbling: false
|
|||
var elem = document.getElementsByTagName('button')[0]; |
|||
elem.addEventListener('click',register,useCapture); |
|||
|
|||
let promises = []; |
|||
promises.push( get_config() ); |
|||
promises.push( get_keys() ); |
|||
|
|||
function register(ev) { |
|||
console.log('register: %o',ev) |
|||
|
|||
let name = document.getElementsByName('name')[0].value; |
|||
let peerid = document.getElementsByName('peerid')[0].value; |
|||
let minerid = document.getElementsByName('minerid')[0].value; |
|||
let account = document.getElementsByName('account')[0].value; |
|||
let bkreward = document.getElementsByName('bkreward')[0].value; |
|||
|
|||
let namep = name.replace(/ /g,'+'); |
|||
let url = api_url + `register?account=${namep}&bkreward=${bkreward}`; |
|||
let data = fetch(url).then(resp => resp.json()); |
|||
console.log('register.data:',data); |
|||
return data; |
|||
} |
|||
|
|||
Promise.all(promises).then( ar => { |
|||
let config = ar[0].config; |
|||
let keys = ar[1].data; |
|||
console.log('config:',config); |
|||
console.log('keys:',keys); |
|||
|
|||
document.getElementsByName('name')[0].value = keys.identity.name; |
|||
document.getElementsByName('peerid')[0].value = keys.identity.public; |
|||
document.getElementsByName('minerid')[0].value = keys.miner.public; |
|||
document.getElementsByName('account')[0].value = keys.distribution.public; |
|||
document.getElementsByName('bkreward')[0].value = config.bkreward; |
|||
|
|||
}). |
|||
catch(console.error); |
|||
|
|||
function get_config() { |
|||
let url = api_url + 'config'; |
|||
return fetch(url).then(resp => resp.json()).catch(console.error) |
|||
} |
|||
function get_keys() { |
|||
let url = api_url + 'getcas?dir=secrets&addr=keys'; |
|||
return fetch(url).then(resp => resp.json()).catch(console.error) |
|||
} |
@ -0,0 +1,21 @@ |
|||
--- |
|||
layout: simple |
|||
base: "../" |
|||
--- |
|||
## Toy-Chain : Miner Registration |
|||
|
|||
name: <input name="name" placeholder="your name"> ([edit][1]) |
|||
<br>peerid: <input name="peerid" placeholder="peerid" size=44> |
|||
<br>minerid: <input name="minerid" placeholder="minerid" size=44> |
|||
<br>account: <input name="account" placeholder="publickey of coinbase destination" size=44> |
|||
<br>block reward:<input name="bkreward" placeholder="block reward" size=3> |
|||
<br><button>register</button> (not implemented yet: use [manual registration][2]) |
|||
|
|||
confirmation: |
|||
<span id=output></span> |
|||
|
|||
<script src="register.js"></script> |
|||
|
|||
|
|||
[1]: /admin/keygen.html |
|||
[2]: /admin/manual-registration.html |
@ -0,0 +1,19 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
## ToyChain Settings |
|||
|
|||
In order to have a functional blockchain you need |
|||
|
|||
1. [generate][1] a node [keypair][2] ([ECDSA] for signing transactions) |
|||
1. [register][4] as a miner by creating a coinbase transaction |
|||
|
|||
|
|||
### comming soon : |
|||
|
|||
1. [new-settings](new-settings.html) |
|||
|
|||
[1]: /admin/keygen.html |
|||
[2]: /api/v0.0/getcas?dir=secrets&addr=keys |
|||
[3]: /api/v0.0/getyml?f=secrets/keys.yml&encode=json |
|||
[4]: /admin/register.html |
@ -0,0 +1,15 @@ |
|||
--- |
|||
layout: simple |
|||
api_url: '/api/v0.0/' |
|||
--- |
|||
## API audit |
|||
|
|||
This api call allow you to audit the server |
|||
|
|||
endpoint: '{{page.api_url}}audit' |
|||
|
|||
|
|||
example: [{{page.api_url}}audit]({{page.api_url}}audit) |
|||
|
|||
|
|||
|
@ -0,0 +1,15 @@ |
|||
--- |
|||
layout: simple |
|||
api_url: '/api/v0.0/' |
|||
--- |
|||
## API cmd |
|||
|
|||
This api call allow you to run generic commands on the server |
|||
|
|||
endpoint: '{{page.api_url}}cmd' |
|||
|
|||
|
|||
example: [{{page.api_url}}cmd/what]({{page.api_url}}cmd/what) |
|||
|
|||
|
|||
|
@ -0,0 +1,22 @@ |
|||
--- |
|||
layout: simple |
|||
api_url: '/api/v0.0/' |
|||
cmd: config |
|||
--- |
|||
## API {{page.cmd}} |
|||
|
|||
This api call allow you see the {{page.cmd}} parameters |
|||
|
|||
endpoint: '{{page.api_url}}{{page.cmd}}' |
|||
|
|||
example: [{{page.api_url}}{{page.cmd}}]({{page.api_url}}{{page.cmd}}) |
|||
|
|||
|
|||
### Alternative |
|||
|
|||
you can also get the config.yml file directly: |
|||
- [$SITE/config.yml](/api/v0.0/getcas?dir=.&addr=config) |
|||
- [$SITE/config.yml](/config.yml) |
|||
|
|||
|
|||
|
@ -0,0 +1,16 @@ |
|||
--- |
|||
layout: simple |
|||
api_url: '/api/v0.0/' |
|||
cmd: env |
|||
--- |
|||
## API {{page.cmd}} |
|||
|
|||
This api call allow you to {{page.cmd}} the server |
|||
|
|||
endpoint: '{{page.api_url}}{{page.cmd}}' |
|||
|
|||
|
|||
example: [{{page.api_url}}{{page.cmd}}]({{page.api_url}}{{page.cmd}}) |
|||
|
|||
|
|||
|
@ -0,0 +1,16 @@ |
|||
--- |
|||
layout: simple |
|||
api_url: '/api/v0.0/' |
|||
cmd: explore |
|||
--- |
|||
## API {{page.cmd}} |
|||
|
|||
This api call allow you to {{page.cmd}} the server |
|||
|
|||
endpoint: '{{page.api_url}}{{page.cmd}}' |
|||
|
|||
|
|||
example: [{{page.api_url}}{{page.cmd}}]({{page.api_url}}{{page.cmd}}) |
|||
|
|||
|
|||
|
@ -0,0 +1,22 @@ |
|||
|
|||
var url = api_url + 'getblock' |
|||
|
|||
var elem = document.getElementsByTagName('div')[0]; |
|||
let button = document.getElementsByTagName('button')[0]; |
|||
|
|||
|
|||
|
|||
let promised_peerid = fetch(url). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
console.log('peerid.obj:',obj); |
|||
let buf = elem.innerHTML; |
|||
buf = buf.replace(':peerid',obj.peerid); |
|||
buf = buf.replace(':name',obj.name); |
|||
elem.innerHTML = buf; |
|||
return obj |
|||
}). |
|||
catch(console.error); |
|||
|
|||
|
|||
console.log('peerid.js loaded'); |
@ -0,0 +1,24 @@ |
|||
--- |
|||
layout: simple |
|||
api_url: '/api/v0.0/' |
|||
cmd: getblock |
|||
--- |
|||
## API {{page.cmd}} |
|||
|
|||
This api call allow you to see the content of a block |
|||
|
|||
endpoint: '{{page.api_url}}{{page.cmd}}' |
|||
|
|||
|
|||
example: [{{page.api_url}}{{page.cmd}}?n=31]({{page.api_url}}{{page.cmd}}?n=31) |
|||
|
|||
n: <input name="n" type="integer" value="" placeholder="height of the block"> |
|||
<br>hash: <input name="hash" type="text" value="" placeholder="hash value of the block"> |
|||
<br>addr: <input name="addr" type="text" value="" placeholder="addr of the block content"> |
|||
<button>view</button> |
|||
|
|||
## json: |
|||
<textarea></textarea> |
|||
|
|||
<script src="getblock.js"></script> |
|||
|
@ -0,0 +1,51 @@ |
|||
--- |
|||
layout: simple |
|||
base: "../" |
|||
version: 'v0.0' |
|||
api_url: '/api/v0.0' |
|||
--- |
|||
# ToyChain API ({{page.version}}) |
|||
|
|||
api endpoint : [http://127.0.0.1:8089/api/{{page.version}}/*][1] |
|||
|
|||
### API development status |
|||
|
|||
1. [status](/docs/status.html) |
|||
2. [chain viewer](/docs/chain.html) |
|||
|
|||
### available commands : |
|||
|
|||
* [{{page.api_url}}/audit](audit.html) |
|||
* [{{page.api_url}}/cmd](cmd.html) |
|||
* [{{page.api_url}}/config](config.html) |
|||
* [{{page.api_url}}/env](env.html) |
|||
* [{{page.api_url}}/getblock](getblock.html) |
|||
* [{{page.api_url}}/getcas](getcas.html) |
|||
* [{{page.api_url}}/getchain](getchain.html) |
|||
* [{{page.api_url}}/getheads](getheads.html) |
|||
* [{{page.api_url}}/getheight](getheight.html) |
|||
* [{{page.api_url}}/getpool](getpool.html) |
|||
* [{{page.api_url}}/gettx](gettx.html) |
|||
* [{{page.api_url}}/mergechain](mergechain.html) |
|||
* [{{page.api_url}}/minepool](minepool.html) |
|||
* [{{page.api_url}}/peerid](peerid.html) |
|||
* [{{page.api_url}}/sendhead](sendhead.html) |
|||
* [{{page.api_url}}/setcas](setcas.html) |
|||
* [{{page.api_url}}/settx](settx.html) |
|||
* [{{page.api_url}}/update](update.html) |
|||
* [{{page.api_url}}/version](version.html) |
|||
|
|||
### CURL commands: |
|||
|
|||
- example of curl commands: [curl-test-script.sh](/curltest.sh) |
|||
|
|||
|
|||
### Initial steps |
|||
|
|||
2. [register][2] yourself as a miner (in order to get the coinbase) |
|||
1. create the [genesis][3] block |
|||
|
|||
[1]: /api/version |
|||
[2]: /admin/register.html |
|||
[3]: /docs/genesis.html |
|||
|
@ -0,0 +1,45 @@ |
|||
|
|||
|
|||
elem = document.getElementsByTagName('table')[0]; |
|||
|
|||
getnodes(); |
|||
async function getnodes() { |
|||
let config = await fetch(api_url + 'config'). |
|||
then(resp => resp.json()). |
|||
then(obj => { return obj.config }). |
|||
catch(console.error); |
|||
console.log('nodes.config:',config); |
|||
|
|||
let n = 1; |
|||
let list = '<ul>'; |
|||
let nodes = []; |
|||
for (node of config.nodes) { |
|||
console.log('nodes.node:',node); |
|||
let [ip,port] = node.split(':'); |
|||
let info = await get_info(node); |
|||
nodes.push(info); |
|||
let url=`http://${node}`; |
|||
let status='offline'; |
|||
let info_url = `${url}${api_url}getinfo`; |
|||
list += `<li>node${n} (:${port}) <a href="${url}">${node}</a> ${status} <a href="${info_url}">information</a></li>\n`; |
|||
console.log('nodes.info:',info); |
|||
n++; |
|||
} |
|||
list += '</ul>'; |
|||
let elem = document.getElementById('list'); |
|||
elem.innerHTML = list; |
|||
return nodes; |
|||
} |
|||
function get_info(node) { |
|||
let [ip,port] = node.split(':'); |
|||
let remote_api_url = `http://${node}${api_url}`; |
|||
let promised = fetch(remote_api_url + 'getinfo'). |
|||
then(resp => resp.json). |
|||
then(obj => { let info = obj.info; return info; }). |
|||
catch(console.error); |
|||
return promised; |
|||
} |
|||
|
|||
|
|||
|
|||
console.log('peerid.js loaded'); |
@ -0,0 +1,31 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# Toy Chain : Peer Networks |
|||
|
|||
We count :n active [nodes][1] on the *[ToyChain][2] MainNet* . |
|||
|
|||
|
|||
| nodename | port | endpoint | status | information | |
|||
|----------|------|----------|--------|-------------| |
|||
| :nname | :port | :url | :status | :info | |
|||
|
|||
<div id=list></div> |
|||
|
|||
<!-- |
|||
<table> |
|||
<tr><th>ip</th><th>port</th><th>endpoint</th><th>information</th></tr> |
|||
<tr><td>:ip</td><td>:port</td><td>:url</td><td>:info</td></tr> |
|||
</table> |
|||
--> |
|||
|
|||
<br>-- |
|||
<br><small>by: <span id=sig></span> src: [md],[css],[js]</small> |
|||
|
|||
<script src="nodes.js"></script> |
|||
|
|||
[1]: /api/v0.0/getnodes |
|||
[2]: /toychain |
|||
[md]: nodes.md |
|||
[css]: /style.css |
|||
[js]: nodes.js |
@ -0,0 +1,20 @@ |
|||
|
|||
var url = api_url + 'peerid' |
|||
|
|||
elem = document.getElementsByTagName('div')[0]; |
|||
|
|||
|
|||
let promised_peerid = fetch(url). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
console.log('peerid.obj:',obj); |
|||
let buf = elem.innerHTML; |
|||
buf = buf.replace(':peerid',obj.peerid); |
|||
buf = buf.replace(':name',obj.name); |
|||
elem.innerHTML = buf; |
|||
return obj |
|||
}). |
|||
catch(console.error); |
|||
|
|||
|
|||
console.log('peerid.js loaded'); |
@ -0,0 +1,15 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# API Peerid |
|||
|
|||
|
|||
This page allow you to see your peerid (i.e. node identity) |
|||
|
|||
``` |
|||
your peerid is :peerid; |
|||
your name is :name; |
|||
``` |
|||
|
|||
|
|||
<script src="peerid.js"></script> |
@ -0,0 +1,53 @@ |
|||
|
|||
let button = document.getElementById('submit'); |
|||
button.addEventListener('click',createtx,false); |
|||
|
|||
loadtx('templ/txexample.yml'); |
|||
|
|||
function createtx() { |
|||
|
|||
let txyml = document.getElementsByName('tx').value; |
|||
|
|||
let promised = fetch(api_url + 'settx?',{method:'POST',data}). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
|
|||
elem = document.getElementById('json'); |
|||
elem.innerText = JSON.stringify(obj); |
|||
|
|||
let bkcontent = obj.bkcontent; |
|||
let txmerkle = bkcontent.txmeta.merkle |
|||
if (typeof(txmerkle) != 'undefined') { |
|||
let list = '<ul>'; |
|||
for (let txa of txmerkle) { |
|||
console.log('getblock.txa:',txa); |
|||
let tx_url = api_url + `gettx?addr=${txa}` |
|||
list += `<li><a href="${tx_url}">${txa}</a></li>` |
|||
} |
|||
list += '</ul>'; |
|||
elem = document.getElementById('list'); |
|||
elem.innerHTML = list; |
|||
} |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
function loadtx(f) { |
|||
let url = api_url + `getyml?f=${f}`; |
|||
let promised = fetch(`/${f}`). |
|||
then(resp => resp.text()). |
|||
then(yaml => { |
|||
document.getElementsByName('tx')[0].value = yaml; |
|||
return yaml; |
|||
}). |
|||
catch(console.error); |
|||
} |
|||
|
|||
// ----------------------------------------------------
|
|||
|
|||
|
|||
console.log('transaction.js loaded'); |
@ -0,0 +1,43 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
## ToyChain Transaction |
|||
|
|||
|
|||
Transactions block is an added record to the block which allow to attached values transfer to the block. |
|||
|
|||
A transaction descript a transfer of value between account protected via [ECC][1] |
|||
(we use [secp256k1][5] see code [ECKeys.pm][2]). |
|||
|
|||
You can register your [keypair][4] in the [admin](/admin/) section under [signup / keygen][3]. |
|||
|
|||
A transaction has inputs, outputs, and signatures, |
|||
in order be valid |
|||
|
|||
- the total of inputs must be greater than the total of ouputs |
|||
- every account on the input side must have enough balance to satisfy the transactions |
|||
- all signature attached to the transaction must be authentic and the signed message not tempered |
|||
|
|||
example of transaction in ([yaml][6] format) |
|||
|
|||
<textarea name=tx rows=7></textarea> |
|||
{% comment %} |
|||
<button id=sign>sign</button> |
|||
<button id=validate>validate</button> |
|||
{%- endcomment -%} |
|||
<button id=submit>submit</button> |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
txaddr: <span id=txaddr><i>:txaddr</i></span> |
|||
|
|||
[1]: https://duckduckgo.com?q=Elliptic+Curve+Cryptography |
|||
[2]: /lib/ECKeys.pm |
|||
[3]: /admin/keygen.html |
|||
[4]: /templ/keys.yml |
|||
[5]: https://duckduckgo.com?q=secp256k1+!g |
|||
[6]: /templ/txexample.yml |
|||
|
|||
<a href="/docs/txpool.html"><button id=txpool>txpool</button></a> |
|||
|
|||
<script src="transaction.js"></script> |
@ -0,0 +1,5 @@ |
|||
# |
|||
|
|||
cat $1 | json_xs -f yaml -t json | tee ${1%.*}.json |
|||
echo '' |
|||
ls -l ${1%.*}.json |
@ -1,45 +1,29 @@ |
|||
--- # toychain's config |
|||
version: 1.12 |
|||
version: 1.13 |
|||
chain: toychain |
|||
apiver: '0.0' |
|||
ipfsgw: 8390 |
|||
|
|||
# ------------------------------------------ |
|||
# node specifics |
|||
port: 8089 |
|||
|
|||
# ------------------------------------------ |
|||
# p2p network |
|||
# api = p2p+1 |
|||
nodes: |
|||
# - 127.0.0.1:8089 |
|||
- 127.0.0.1:8091 |
|||
- 127.0.0.2:8093 |
|||
- 127.0.0.3:8095 |
|||
- 127.0.0.4:8097 |
|||
- 127.0.0.5:8099 |
|||
|
|||
# ------------------------------------------ |
|||
# 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 |
|||
|
|||
reward: 100 |
|||
|
|||
# Proof of Work option |
|||
difficulty: 5 |
|||
maxdiff: 7 |
|||
# CAstore options |
|||
trackmode: 1 |
|||
# ------------------------------------------ |
@ -1,23 +0,0 @@ |
|||
--- # toychain's config |
|||
version: 1.06 |
|||
chain: toychain |
|||
apiver: '0.0' |
|||
ipfsgw: 8390 |
|||
port: 8089 |
|||
|
|||
# p2p network = api+1 |
|||
apis: |
|||
- 127.0.0.1:8091 |
|||
- 127.0.0.2:8093 |
|||
- 127.0.0.3:8095 |
|||
- 127.0.0.4:8097 |
|||
- 127.0.0.5:8099 |
|||
|
|||
# block parameters : |
|||
bkver: 0 |
|||
bkreward: 100 |
|||
# Proof of Work option |
|||
difficulty: 5 |
|||
maxdiff: 7 |
|||
# CAstore options |
|||
trackmode: 1 |
@ -0,0 +1,10 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# Unspend TXO |
|||
|
|||
The unspend transaction outputs are defining the (mutable) state of the blockchain, |
|||
we choose to aggregate them per addresses such that we only have to store the balance of addresses which |
|||
have a positive balance; rather than maintaning a complete list of unspend transactions. |
|||
|
|||
- [UTXO](/api/v0.0/getjson?obj=TXPOOL::UTXO) |
@ -0,0 +1,111 @@ |
|||
|
|||
let button = document.getElementsByTagName('button')[0]; |
|||
button.addEventListener('click',getblock,false); |
|||
|
|||
|
|||
function getblock() { |
|||
|
|||
let n = document.getElementsByName('n').value; |
|||
let hash = document.getElementsByName('hash').value; |
|||
let addr = document.getElementsByName('addr').value; |
|||
let query = []; |
|||
if (n != '') { |
|||
query.push(`n=${n}`) |
|||
} else if (hash != '') { |
|||
query.push(`hash=${hash}`) |
|||
} else if (addr != '') { |
|||
query.push(`addr=${addr}`) |
|||
} |
|||
|
|||
document.getElementById('comment').innerText = ''; |
|||
let promised = fetch(api_url + 'getblock?' + query.join('&')). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
let elem; |
|||
let payload_value = obj.bkcontent.data.payload; |
|||
let payload_url = `/api/getblock?addr=${obj.bkaddr}` |
|||
if (payload_value.match('/ipfs/')) { |
|||
payload_url = 'https://ipfs.blockringtm.ml'+ payload_value |
|||
} else if (payload_value.match('/https?:|\.htm/')) { |
|||
payload_url = payload_value; |
|||
} |
|||
let payload_link = `<a href="${payload_url}">${payload_value}</a>`; |
|||
|
|||
document.getElementsByName('hash')[0].value = obj.bkhash; |
|||
document.getElementsByName('addr')[0].value = obj.bkaddr; |
|||
document.getElementById('prev').innerHTML = `<a href="/api/v0.0/getblock?hash=${obj.bkprev}">${obj.bkprev}</a>`; |
|||
document.getElementById('seq').innerText = obj.bkcontent.data.seq; |
|||
document.getElementById('payload').innerHTML = payload_link; |
|||
document.getElementById('comment').innerText = obj.bkcontent.data.comment; |
|||
document.getElementById('txroot').innerText = obj.bkcontent.meta.txroot || '?'; |
|||
document.getElementById('hash').innerText = obj.bkhash |
|||
document.getElementById('pow').innerText = obj.pow |
|||
document.getElementById('api').innerHTML = `(<a href="/api/v0.0/getblock?hash=${obj.bkhash}">json</a>)`; |
|||
|
|||
elem = document.getElementById('json'); |
|||
elem.innerText = JSON.stringify(obj); |
|||
|
|||
let bkcontent = obj.bkcontent; |
|||
let txmerkle = bkcontent.txmeta.merkle |
|||
if (typeof(txmerkle) != 'undefined') { |
|||
let list = '<ul>'; |
|||
for (let txa of txmerkle) { |
|||
console.log('getblock.txa:',txa); |
|||
let tx_url = api_url + `gettx?addr=${txa}` |
|||
list += `<li><a href="${tx_url}">${txa}</a></li>` |
|||
} |
|||
list += '</ul>'; |
|||
elem = document.getElementById('list'); |
|||
elem.innerHTML = list; |
|||
} |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
|
|||
// ----------------------------------------------------
|
|||
|
|||
async function getnodes() { |
|||
let config = await fetch(api_url + 'config'). |
|||
then(resp => resp.json()). |
|||
then(obj => { return obj.config }). |
|||
catch(console.error); |
|||
console.log('nodes.config:',config); |
|||
|
|||
let n = 1; |
|||
let list = '<ul>'; |
|||
let nodes = []; |
|||
for (node of config.nodes) { |
|||
console.log('nodes.node:',node); |
|||
let [ip,port] = node.split(':'); |
|||
let info = await get_info(node); |
|||
nodes.push(info); |
|||
let url=`http://${node}`; |
|||
let status='offline'; |
|||
let info_url = `${url}${api_url}getinfo`; |
|||
list += `<li>node${n} (:${port}) <a href="${url}">${node}</a> ${status} <a href="${info_url}">information</a></li>\n`; |
|||
console.log('nodes.info:',info); |
|||
n++; |
|||
} |
|||
list += '</ul>'; |
|||
let elem = document.getElementById('list'); |
|||
elem.innerHTML = list; |
|||
return nodes; |
|||
} |
|||
function get_info(node) { |
|||
let [ip,port] = node.split(':'); |
|||
let remote_api_url = `http://${node}${api_url}`; |
|||
let promised = fetch(remote_api_url + 'getinfo'). |
|||
then(resp => resp.json). |
|||
then(obj => { let info = obj.info; return info; }). |
|||
catch(console.error); |
|||
return promised; |
|||
} |
|||
|
|||
|
|||
|
|||
console.log('heads.js loaded'); |
@ -0,0 +1,39 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain's Block |
|||
|
|||
A block in ToyChain blockchain is 80 bytes |
|||
|
|||
n: <input name=n size=3> <span id=comment></span> |
|||
<br>hash: <input name=hash size=43> |
|||
<br>addr: <input name=addr size=43> |
|||
<br>prev: <span id=prev><i>:prev</i></span> |
|||
<br><button>fetch</button> |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
Here is the content of the requested block <span id=api></span> |
|||
|
|||
- seq: <span id=seq>#.</span> |
|||
payload : "<span id=payload><i>:payload</i></span>" |
|||
- hash: <span id=hash><i>:hash</i></span> |
|||
pow: <span id=pow><i>:pow</i></span> |
|||
- txroot: <span id=txroot><i>:txroot</i></span> |
|||
|
|||
<div id=content></div> |
|||
|
|||
List of attached transactions : |
|||
|
|||
<div id=list></div> |
|||
|
|||
|
|||
|
|||
<script src="block.js"></script> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,30 @@ |
|||
|
|||
|
|||
getchain(); |
|||
function getchain() { |
|||
let promised = fetch(api_url + 'getchain'). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
let elem = document.getElementById('json'); |
|||
elem.innerText = JSON.stringify(obj); |
|||
|
|||
let list = '<pre>'; |
|||
for (let bh of obj.chain) { |
|||
console.log('getchain.bh:',bh); |
|||
let blk_url = api_url + `getblock?hash=${bh}`; |
|||
list += `<a href="${blk_url}">${bh}</a>\n` |
|||
} |
|||
list += '</pre>'; |
|||
elem = document.getElementById('list'); |
|||
elem.innerHTML = list; |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
// ----------------------------------------------------
|
|||
console.log('chain.js loaded'); |
|||
|
@ -0,0 +1,22 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain's Chain View |
|||
|
|||
The ToyChain blockchain is a list of basic 80 Bytes blocks, |
|||
each block is address with a base58 encoded hash of 32B |
|||
(i.e. ``32 * l(235) / l(58) = ~44 char.``). |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
Here is the list all the blocks in the chain |
|||
|
|||
<div id=list></div> |
|||
|
|||
See also [HEADs][1] |
|||
|
|||
<script src="chain.js"></script> |
|||
|
|||
[1]: /docs/heads.html |
|||
|
|||
|
@ -0,0 +1,23 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# block difficulties |
|||
|
|||
we use [hashcash][1] as a mechanism to protect the blockchain from a Sybil Attack. |
|||
|
|||
The difficulty is the number of hexadecimal digit we have to "resolve" in the block hash. |
|||
|
|||
Finding a block hash than match the required difficuly is the "work" |
|||
and the hash itself is the [*proof of work*][1]. |
|||
|
|||
example: block [Z9Pa9kcag3TBc6EX671u6Zwk7N6M7jTuQ5HPtjzDrpx4f][2] has is matching a difficulty of 4 |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
[1]: /docs/pow.html |
|||
[2]: /api/0.0/getblock?hash=Z9Pa9kcag3TBc6EX671u6Zwk7N6M7jTuQ5HPtjzDrpx4f |
@ -0,0 +1,27 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# Toy Chain Explorer |
|||
|
|||
The API server has an [explore][1] endpoint that allows to view all of the chain's "[internals][2]" |
|||
|
|||
You can explore the chain, blocks, transaction and more ... |
|||
|
|||
- get the [HEADs][3] |
|||
- get the [chain][4] |
|||
- get a [block][5] |
|||
- get the [txpool][6] |
|||
- get the [utxo][7] state |
|||
- get a [transaction][8] |
|||
- get [nodes][9] |
|||
|
|||
[1]: /api/explore.html |
|||
[2]: /docs/internals.html |
|||
|
|||
[3]: /docs/heads.html |
|||
[4]: /docs/chain.html |
|||
[5]: /docs/block.html |
|||
[6]: /docs/txpool.html |
|||
[7]: /docs/utxo.html |
|||
[8]: /docs/transactions.html |
|||
[9]: /docs/nodes.html |
@ -0,0 +1,57 @@ |
|||
const useCapture = false; // capture, bubbling: false
|
|||
|
|||
button = document.getElementsByTagName('button')[0]; |
|||
button.addEventListener('click',genesis,false); |
|||
console.log(button) |
|||
var payload = 'QmVnvdASdT1c9fJ2mcDhTAYhb63gcFRkiRmJW7NAm1YcSf'; |
|||
//var txcoinhash = 'ZCBtx7Wg59hvMogWDchKVcGUMo68qDe2dkRfzaskAh3G';
|
|||
//var prevhash = 'Z9BEeWD4Mww7yrXyPRXrfM2y6FxsQGfaNPzC8DxWq4ATq';
|
|||
var pow = '11501558695957493006'; |
|||
var comment = 'Genesis ~ Manuela J. Savina'; |
|||
|
|||
// get default values (from nodes) ...
|
|||
let promised_config = fetch(api_url + 'config'). |
|||
then(resp => resp.json()). |
|||
then(obj => { return obj.config }). |
|||
catch(console.error) |
|||
|
|||
let promised_nullhash = fetch(api_url + 'getjson?obj=Genesis::nullhash'). |
|||
then(resp => resp.json()). |
|||
then(obj => { console.log('promised_nullhash.obj:',obj) |
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
|
|||
Promise.all([promised_config, promised_nullhash]).then( _ => { |
|||
let [config,nullhash] = _; |
|||
console.log('genesis.config:',config); |
|||
document.getElementsByName('payload')[0].value = payload; |
|||
document.getElementsByName('txcoinhash')[0].value = config.txcoin; |
|||
document.getElementsByName('prevhash')[0].value = nullhash; |
|||
document.getElementsByName('pow')[0].value = pow; |
|||
document.getElementsByName('comment')[0].value = comment; |
|||
}).catch(console.error); |
|||
|
|||
|
|||
function genesis(ev) { |
|||
console.log('genesis.ev: %o',ev); |
|||
let query = { |
|||
"payload": document.getElementsByName('payload')[0].value, |
|||
"txcoin": document.getElementsByName('txcoinhash')[0].value, |
|||
"bkprev": document.getElementsByName('prevhash')[0].value, |
|||
"pow": document.getElementsByName('pow')[0].value, |
|||
"comment": document.getElementsByName('comment')[0].value |
|||
}; |
|||
query_string = Object.keys(query).map( k => k +'='+ query[k] ).join('&'); |
|||
let url = api_url + `creategen?${query_string}`; |
|||
document.getElementByName('pow')[0].value = 'working...'; |
|||
let promised = fetch(url). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
console.log('genesis.obj:',obj); |
|||
document.getElementsByName('pow')[0].value = obj.pow; |
|||
}). |
|||
catch(console.error); |
|||
} |
|||
|
|||
|
@ -0,0 +1,27 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain Genesis Block |
|||
|
|||
The genesis block is a regular block with |
|||
only one [coinbase][1] transaction |
|||
and a previous link that point to the [NullBlock][3] |
|||
|
|||
|
|||
A block is consist of the following part : |
|||
|
|||
1. a payload <input name=payload> |
|||
2. a [coinbase][2] transaction <input name=txcoinhash> |
|||
<!--2. a transactions list (merkle tree) <input name=txpool disabled> --> |
|||
3. a link to the previous block <input name=prevhash disabled> |
|||
4. a proof of work <input name=pow> |
|||
5. an optional comment <input name=comment> |
|||
|
|||
<button>create</button> |
|||
|
|||
|
|||
[1]: /docs/coinbase.html |
|||
[2]: /api/v0.0/getyml?f=templ/txcoin.yml&encode=json |
|||
[3]: /api/v0.0/getcas?addr=nullblock&dir=templ |
|||
|
|||
<script src="genesis.js"></script> |
@ -0,0 +1,74 @@ |
|||
|
|||
|
|||
getheads(); |
|||
function getheads() { |
|||
let promised = fetch(api_url + 'getheads'). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
let elem = document.getElementById('json'); |
|||
elem.innerText = JSON.stringify(obj); |
|||
|
|||
let list = '<ul>'; |
|||
for (let b of obj.HEADs) { |
|||
console.log('getheads.b:',b); |
|||
let blk_url = api_url + `getblock?hash=${b.bkhash}`; |
|||
let content_url = api_url + `getblock?addr=${b.bkaddr}`; |
|||
let peerid = b.bkcontent.audit.peerid; |
|||
let whois_url = api_url + `whois?pub=${peerid}` |
|||
list += `<li><a href="${blk_url}">${b.bkhash}</a> by <a href="${whois_url}">${peerid}</a>: `+ |
|||
`<a href="${content_url}">${b.bkaddr}</a> ${b.bkprev} pow:${b.pow}</li>`; |
|||
} |
|||
list += '</ul>'; |
|||
elem = document.getElementById('list'); |
|||
elem.innerHTML = list; |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
|
|||
// ----------------------------------------------------
|
|||
|
|||
async function getnodes() { |
|||
let config = await fetch(api_url + 'config'). |
|||
then(resp => resp.json()). |
|||
then(obj => { return obj.config }). |
|||
catch(console.error); |
|||
console.log('nodes.config:',config); |
|||
|
|||
let n = 1; |
|||
let list = '<ul>'; |
|||
let nodes = []; |
|||
for (node of config.nodes) { |
|||
console.log('nodes.node:',node); |
|||
let [ip,port] = node.split(':'); |
|||
let info = await get_info(node); |
|||
nodes.push(info); |
|||
let url=`http://${node}`; |
|||
let status='offline'; |
|||
let info_url = `${url}${api_url}getinfo`; |
|||
list += `<li>node${n} (:${port}) <a href="${url}">${node}</a> ${status} <a href="${info_url}">information</a></li>\n`; |
|||
console.log('nodes.info:',info); |
|||
n++; |
|||
} |
|||
list += '</ul>'; |
|||
let elem = document.getElementById('list'); |
|||
elem.innerHTML = list; |
|||
return nodes; |
|||
} |
|||
function get_info(node) { |
|||
let [ip,port] = node.split(':'); |
|||
let remote_api_url = `http://${node}${api_url}`; |
|||
let promised = fetch(remote_api_url + 'getinfo'). |
|||
then(resp => resp.json). |
|||
then(obj => { let info = obj.info; return info; }). |
|||
catch(console.error); |
|||
return promised; |
|||
} |
|||
|
|||
|
|||
|
|||
console.log('heads.js loaded'); |
@ -0,0 +1,23 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain's HEADs |
|||
|
|||
The ToyChain blockchain as many as head as there are nodes that holds differents forks. |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
Here is the list with their respective owners |
|||
|
|||
<div id=list></div> |
|||
|
|||
|
|||
|
|||
<script src="heads.js"></script> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,44 @@ |
|||
|
|||
// getting node information ...
|
|||
|
|||
info(); |
|||
function info() { |
|||
let promised = fetch(api_url + 'getinfo'). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
document.getElementById('json').innerText = JSON.stringify(obj.info); |
|||
|
|||
let p = document.getElementsByTagName('p')[0]; |
|||
let buf = p.innerHTML; |
|||
buf = buf.replace(':nodeid',obj.info.nodeid); |
|||
buf = buf.replace(':port',obj.info.port); |
|||
buf = buf.replace(':botname',obj.info.botname); |
|||
buf = buf.replace(':owner',obj.info.owner); |
|||
buf = buf.replace(':peerid',obj.info.peerid); |
|||
buf = buf.replace(':height',obj.info.height); |
|||
buf = buf.replace(/:head/g,obj.info.head); |
|||
buf = buf.replace(/:genesis/g,obj.info.genesis); |
|||
|
|||
p.innerHTML = buf; |
|||
|
|||
if (typeof(obj.api) != 'undefined') { |
|||
let list = '<ol>'; |
|||
for (let item of obj.api) { |
|||
console.log('test.item:',item); |
|||
let url = api_url + `getcas?addr=${item}`; |
|||
list += `<li><a href="${url}">${item}</a></li>\n` |
|||
} |
|||
list += '</ol>'; |
|||
document.getElementById('list').innerHTML = list; |
|||
} |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
// ----------------------------------------------------
|
|||
console.log('info.js loaded'); |
|||
|
@ -0,0 +1,29 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# Nodes' Information |
|||
|
|||
<p> |
|||
nodeid: :nodeid |
|||
<br>port: :port |
|||
<br>botname: :botname |
|||
<br>owner: :owner |
|||
<br>peerid: :peerid |
|||
<br> |
|||
<br>block height: :height |
|||
<br>head bkhash: <a href="/api/v0.0/getblock?hash=:head">:head</a> |
|||
<br>genesis bkhash: <a href="/api/v0.0/getblock?hash=:genesis">:genesis</a> |
|||
</p> |
|||
|
|||
|
|||
<textarea id=json></textarea> |
|||
([json](/api/0.0/getjson?obj=result)) |
|||
|
|||
<div id=list></div> |
|||
|
|||
<a href="/docs/"><button id=docs>documentation</button></a> |
|||
|
|||
<script src="info.js"></script> |
|||
|
|||
|
|||
|
@ -0,0 +1,30 @@ |
|||
|
|||
|
|||
minepool(); |
|||
function minepool() { |
|||
let promised = fetch(api_url + 'minepool'). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
document.getElementById('json').innerText = JSON.stringify(obj); |
|||
|
|||
if (typeof(obj.txpool) != 'undefined') { |
|||
let list = '<ol>'; |
|||
for (let txa of obj.txpool) { |
|||
console.log('getpool.bh:',txa); |
|||
let tx_url = api_url + `gettx?addr=${txa}`; |
|||
list += `<li><a href="${tx_url}">${txa}</a></li>\n` |
|||
} |
|||
list += '</ol>'; |
|||
document.getElementById('list').innerHTML = list; |
|||
} |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
// ----------------------------------------------------
|
|||
console.log('txpool.js loaded'); |
|||
|
@ -0,0 +1,30 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain's Mining |
|||
|
|||
The ToyChain Mining is the action of |
|||
|
|||
- creating a new block to record transaction in the [txpool](txpool.html) |
|||
- attaching the block to the [HEAD](heads.html) of the chain. |
|||
- computing the hash of this block with enough [PoW](pow.html) |
|||
- advertizing the new head of the chain |
|||
|
|||
height: <span id=height></span> |
|||
HEAD: <span id=head></span> |
|||
new block: <span id=new></span> |
|||
|
|||
|
|||
<textarea id=json></textarea> |
|||
([json][1]) |
|||
|
|||
<div id=list></div> |
|||
|
|||
<a href="/docs/chain.html"><button id=chain>chain view</button></a> |
|||
|
|||
|
|||
<script src="minepool.js"></script> |
|||
|
|||
|
|||
[1]: /api/0.0/getjson?obj=result |
|||
|
@ -0,0 +1,24 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain's Mining |
|||
|
|||
The ToyChain Mining is the action of |
|||
|
|||
- creating a new block to record transaction in the [txpool](txpool.html) |
|||
- attaching the block to the [HEAD](heads.html) of the chain. |
|||
- computing the hash of this block with enough [PoW](pow.html) |
|||
- advertizing the new head of the chain |
|||
|
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
<div id=list></div> |
|||
|
|||
<a href="/docs/chain.html"><button id=chain>chain view</button></a> |
|||
|
|||
|
|||
<script src="mining.js"></script> |
|||
|
|||
|
|||
|
@ -0,0 +1,30 @@ |
|||
|
|||
|
|||
getnodes(); |
|||
function getnodes() { |
|||
let promised = fetch(api_url + 'getnodes'). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
document.getElementById('json').innerText = JSON.stringify(obj.api); |
|||
|
|||
if (typeof(obj.api) != 'undefined') { |
|||
let list = '<ol>'; |
|||
for (let node of obj.api) { |
|||
console.log('getnodes.node:',node); |
|||
let url = `http:/${node}/docs/chain.html` |
|||
list += `<li><a href="${url}">${node}</a></li>\n` |
|||
} |
|||
list += '</ol>'; |
|||
document.getElementById('list').innerHTML = list; |
|||
} |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
// ----------------------------------------------------
|
|||
console.log('nodes.js loaded'); |
|||
|
@ -0,0 +1,21 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain Nodes |
|||
|
|||
getting nodes list : fixed network here (no discovery). |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
<div id=list></div> |
|||
> <a href="javascript:location.href=location.origin+'/docs/chain.html';">this node</a> |
|||
|
|||
|
|||
### API commands |
|||
|
|||
- [/api/v0.0/getnodes](/api/v0.0/getnodes) |
|||
|
|||
<script src="nodes.js"></script> |
|||
|
|||
<a href="/docs/"><button id=docs>documentation</button></a> |
|||
|
@ -0,0 +1,27 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# API implementation status ... |
|||
|
|||
### currently available |
|||
|
|||
- [heads](/docs/heads.html) |
|||
- [chain](/docs/chain.html) |
|||
- [block](/docs/block.html) |
|||
- [transaction](/docs/transactions.html) |
|||
- [txpool](/docs/txpool.html) |
|||
|
|||
### api commands |
|||
|
|||
- [utxo](/api/utxo.html) |
|||
- [gettx](/api/gettx.html) |
|||
- [settx](/api/settx.html) |
|||
|
|||
|
|||
### coming soon |
|||
|
|||
- [UTXO](/docs/UTXO.html) |
|||
- [explore](/api/explore.html) |
|||
- [internals](/docs/internals.html) |
|||
- [register](/admin/register.html) |
|||
- [genesis](/docs/genesis.html) |
@ -0,0 +1,30 @@ |
|||
|
|||
|
|||
testing(); |
|||
function testing() { |
|||
let promised = fetch(api_url + 'getnodes'). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
document.getElementById('json').innerText = JSON.stringify(obj.api); |
|||
|
|||
if (typeof(obj.api) != 'undefined') { |
|||
let list = '<ol>'; |
|||
for (let item of obj.api) { |
|||
console.log('test.item:',item); |
|||
let url = api_url + `getcas?addr=${item}`; |
|||
list += `<li><a href="${url}">${item}</a></li>\n` |
|||
} |
|||
list += '</ol>'; |
|||
document.getElementById('list').innerHTML = list; |
|||
} |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
// ----------------------------------------------------
|
|||
console.log('txpool.js loaded'); |
|||
|
@ -0,0 +1,42 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# Testing the ToyChain |
|||
|
|||
testing the API ... |
|||
|
|||
### internals |
|||
|
|||
- [getnodes](/api/v0.0/getnodes) |
|||
- [chain](/api/v0.0/getjson?obj=toychain::chain) |
|||
- [TXPOOL](/api/v0.0/getjson?obj=TXPOOL::TXPOOL) |
|||
- [UTXO](/api/v0.0/getjson?obj=TXPOOL::UTXO) |
|||
- [getregs](/api/v0.0/getjson?obj=registration) |
|||
- [getruntime](/api/v0.0/getjson?obj=runtime) |
|||
- [txcoin](/api/v0.0/getjson?obj=Genesis::txcoin) |
|||
- [getnick](/api/v0.0/getjson?obj=nicknames) |
|||
- [getkeys](/api/v0.0/getjson?obj=keys) |
|||
|
|||
### source : |
|||
|
|||
- [config](/lib/config.pm) |
|||
- [toychain](/lib/toychain.pm) |
|||
- [Chain](/lib/Chain.pm) |
|||
- [ECKeys](/lib/ECKeys.pm) |
|||
- [Genesis](/lib/Genesis.pm) |
|||
- [API](/lib/API.pm) |
|||
|
|||
|
|||
### nodes : |
|||
|
|||
<div id=list></div> |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
<a href="/docs/"><button id=docs>documentation</button></a> |
|||
|
|||
|
|||
<script src="test.js"></script> |
|||
|
|||
|
|||
|
@ -0,0 +1,51 @@ |
|||
|
|||
let button = document.getElementsByTagName('button')[0]; |
|||
button.addEventListener('click',gettx,false); |
|||
|
|||
|
|||
function gettx() { |
|||
|
|||
let addr = document.getElementsByName('addr')[0].value; |
|||
let url = api_url + 'gettx?addr=' + addr; |
|||
document.getElementById('url').innerHTML = `<a href=${url}>${url}</a>`; |
|||
|
|||
let promised = fetch(url). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
let elem = document.getElementById('json'); |
|||
elem.innerText = JSON.stringify(obj.tx); |
|||
|
|||
console.log('obj.tx',obj.tx); |
|||
document.getElementById('txroot').innerText = obj.tx.txroot |
|||
document.getElementById('pow').innerText = obj.tx.pow |
|||
|
|||
let list = '' |
|||
for (let i of obj.tx.inputs) { |
|||
public = Object.keys(i)[0]; |
|||
list += `<li>${public} ${i[public]}</li>`; |
|||
} |
|||
document.getElementById('in').innerHTML = list; |
|||
list = '' |
|||
for (let o of obj.tx.outputs) { |
|||
public = Object.keys(o)[0]; |
|||
list += `<li>${public} ${o[public]}</li>`; |
|||
} |
|||
document.getElementById('out').innerHTML = list; |
|||
list = '' |
|||
for (let s of obj.tx.signatures) { |
|||
public = Object.keys(s)[0]; |
|||
list += `<li>${public} ${s[public][0]}</li>`; |
|||
} |
|||
document.getElementById('sig').innerHTML = list; |
|||
|
|||
document.getElementById('yaml').innerText = obj.yaml; |
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj.tx; }); |
|||
|
|||
} |
|||
|
|||
|
|||
// ----------------------------------------------------
|
|||
console.log('transactions.js loaded'); |
@ -0,0 +1,46 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# Transactions |
|||
|
|||
|
|||
There are two types: |
|||
|
|||
1. mempool transactions : pending validation |
|||
2. block transactions : confirmed transactions (organized in merkle tree) |
|||
|
|||
You can create a [transaction][1] using the [settx][2] [API][3] call. |
|||
|
|||
You can view transactions with the address : |
|||
|
|||
addr: <input name=addr size=38 value="ZtxZojTad7bmjVKH67eeRGeaEKkTNQtEdiTxEMKFXGbC"> |
|||
<button>view</button> |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
txroot: <span id=txroot></span> |
|||
<br>pow: <span id=pow></span> |
|||
<br>url: <span id=url></span> |
|||
|
|||
### inputs |
|||
|
|||
<ol id=in></ol> |
|||
|
|||
### outputs |
|||
|
|||
<ol id=out></ol> |
|||
|
|||
### signatures |
|||
|
|||
<ol id=sig></ol> |
|||
|
|||
---- |
|||
|
|||
<pre id=yaml></pre> |
|||
|
|||
|
|||
[1]: /api/transaction.html |
|||
[2]: /api/settx.html |
|||
[3]: /api/ |
|||
|
|||
<script src="transactions.js"></script> |
@ -0,0 +1,28 @@ |
|||
|
|||
|
|||
getpool(); |
|||
function getpool() { |
|||
let promised = fetch(api_url + 'getpool'). |
|||
then(resp => resp.json()). |
|||
then(obj => { |
|||
document.getElementById('json').innerText = JSON.stringify(obj); |
|||
|
|||
let list = '<ol>'; |
|||
for (let txa of obj.txpool) { |
|||
console.log('getpool.bh:',txa); |
|||
let tx_url = api_url + `gettx?addr=${txa}`; |
|||
list += `<li><a href="${tx_url}">${txa}</a></li>\n` |
|||
} |
|||
list += '</ol>'; |
|||
document.getElementById('list').innerHTML = list; |
|||
|
|||
return obj; |
|||
}). |
|||
catch(console.error); |
|||
promised.then(obj => { console.log('obj:',obj); return obj; }); |
|||
|
|||
} |
|||
|
|||
// ----------------------------------------------------
|
|||
console.log('txpool.js loaded'); |
|||
|
@ -0,0 +1,21 @@ |
|||
--- |
|||
layout: simple |
|||
--- |
|||
# ToyChain's TxPool View |
|||
|
|||
The ToyChain [TxPool][1] is a list of pending transactions |
|||
|
|||
<textarea id=json></textarea> |
|||
|
|||
Here is the list all the transactions in the pool |
|||
|
|||
<div id=list></div> |
|||
|
|||
<a href="/docs/minepool.html"><button id=minepool>minepool</button></a> |
|||
|
|||
|
|||
<script src="txpool.js"></script> |
|||
|
|||
[1]: /api/v0.0/getjson?obj=TXPOOL::TXPOOL |
|||
|
|||
|
@ -1,32 +0,0 @@ |
|||
#!/usr/bin/perl |
|||
# |
|||
# testing out ecdsa key generation ... |
|||
|
|||
use Crypt::PK::ECC; |
|||
use YAML::Syck qw(Dump); |
|||
|
|||
#Key generation |
|||
my $pk = Crypt::PK::ECC->new(); |
|||
$pk->generate_key('secp256k1'); |
|||
my $private_der = $pk->export_key_der('private'); |
|||
|
|||
my $public_pem = $pk->export_key_pem('public'); |
|||
|
|||
local *PK; |
|||
open PK,'>','eckey-priv.der'; binmode(PK); |
|||
print PK $private_der; |
|||
close |
|||
open PK,'>','eckey-pub.pem'; |
|||
print PK $public_pem; |
|||
close PK; |
|||
|
|||
open PK,'>','eckey.yml'; |
|||
print PK "--- # eckey\n"; |
|||
printf PK "pk: %s\n",Dump($pk->key2hash); |
|||
printf PK "...\n"; |
|||
close PK; |
|||
|
|||
|
|||
exit $?; |
|||
|
|||
1; # $Source: /my/perl/script/eckeygen.pl $ |
@ -1 +1 @@ |
|||
Subproject commit d4bea95cde2025454813231b121ffffa846eee0a |
|||
Subproject commit d1fd3ef3a87ec1bd14c33ef19e106c86fde4e78f |
@ -1 +1 @@ |
|||
salt: 8163726777753892901 |
|||
salt: 8163726777754382880 |
@ -0,0 +1,14 @@ |
|||
|
|||
|
|||
set -e |
|||
for f in tx*.yml; do |
|||
echo f: $f |
|||
#cat $f | sed -e "s/$/%0a/g" | curl -s -X POST http://127.0.0.1:8089/api/0.0/istxvalid -d @- |
|||
cat $f | json_xs -f yaml | grep -v 'null' | curl -s -X POST http://127.0.0.1:8089/api/0.0/settx -d @- |
|||
echo '' |
|||
done |
|||
for f in tx*.json; do |
|||
cat $f | curl -s -X POST http://127.0.0.1:8089/api/0.0/settx -d @- |
|||
echo '' |
|||
done |
|||
|
@ -0,0 +1,17 @@ |
|||
--- # toychain's runtime state |
|||
|
|||
# cashash mode |
|||
trackmode: 1 |
|||
# verification node |
|||
skip_balance_check: 1 |
|||
|
|||
# special blocks: |
|||
genhash: ~ |
|||
nullhash: ~ |
|||
|
|||
# transactions: |
|||
txgen: ~ |
|||
txcoin: ~ |
|||
|
|||
# misc. |
|||
ipfsgw: 8390 |
@ -0,0 +1 @@ |
|||
salt: 3029492618445148610 |
@ -0,0 +1,20 @@ |
|||
--- |
|||
inputs: |
|||
- |
|||
Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 11 |
|||
outputs: |
|||
- |
|||
ZF2egd6zrw6EcLJt5TmKPzjMSMpyVmkRCKKehLaaakZEU: 7 |
|||
- |
|||
ZCCWdhnf5aQ3oFMt6JxULAjmCNkB8DNaLpB3Fzcc6V3PN: 1 |
|||
- |
|||
Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 3 |
|||
payload: This is an example of transaction |
|||
signatures: |
|||
- |
|||
Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: |
|||
- Zan1RjNCSDtQtvuBVNvwvNKwWDwN9tPRGFbmmRoJQFeophTFHq6cAsvskowPgHpKWR1LUc5usEwqRLyxcGLzYYc91k8VENiT4H |
|||
- |
|||
ZCCWdhnf5aQ3oFMt6JxULAjmCNkB8DNaLpB3Fzcc6V3PN: |
|||
- Z381YwxTinKz9QgQQzbRSfi4C9B9GTHJhv6TPiq5qeffrLneeST9QtNeueMXsUVzXmA1jTycJAti5D5YdZRojx7kTDRVv1WoD |
|||
timestamp: '1623683269225552702' |
@ -0,0 +1 @@ |
|||
{"signatures":[{"michelc":["ZHjX1cinn46FbTioY43qo2ZmfgnjZzXKRMiVN3tZRbxkzg61hNdKRoGptqeFa2tT5kzHqrSUTNcHFTfsLYSz5eDRGXmL3wzc1Gt","2021-06-14 19.54.28","[michelc,0,a]"]},{"anonymous":["ZHjX1cin92axvE1YtoPZyakN1HSFZmXpFxqSVqaWz1S3eyVA5rxTohXUcjcR5sPG9apfTEy34dSUyMPPuN2ngQNDMEFrEgZqbMN","2021-06-14 19.54.28","[anonymous,0,a]"]}],"inputs":[{"ZX3hz85Vayc3Nhfs43ADhTeJXkDJ3fnXtfRiDW4pQzYRQ":"6"}],"nonce":"3976914969180171529","pow":"3976914969180292365","timestamp":"1623693268225555737","outputs":[{"Z24zaLMH6SCfAoC8ndS9XunjrkVpZW5tprhrZdSq3CcXWQ":"3"},{"Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq":"2"}],"message":"This is an other example for transaction"} |
@ -0,0 +1,23 @@ |
|||
--- |
|||
message: This is an other example for transaction |
|||
inputs: |
|||
- ZX3hz85Vayc3Nhfs43ADhTeJXkDJ3fnXtfRiDW4pQzYRQ: 3 |
|||
nonce: '3976914969180171529' |
|||
outputs: |
|||
- |
|||
Z24zaLMH6SCfAoC8ndS9XunjrkVpZW5tprhrZdSq3CcXWQ: 3 |
|||
- |
|||
Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 2 |
|||
pow: '3976914969180292365' |
|||
signatures: |
|||
- |
|||
michelc: |
|||
- ZHjX1cinn46FbTioY43qo2ZmfgnjZzXKRMiVN3tZRbxkzg61hNdKRoGptqeFa2tT5kzHqrSUTNcHFTfsLYSz5eDRGXmL3wzc1Gt |
|||
- 2021-06-14 19.54.28 |
|||
- "[michelc,0,a]" |
|||
- |
|||
anonymous: |
|||
- ZHjX1cin92axvE1YtoPZyakN1HSFZmXpFxqSVqaWz1S3eyVA5rxTohXUcjcR5sPG9apfTEy34dSUyMPPuN2ngQNDMEFrEgZqbMN |
|||
- 2021-06-14 19.54.28 |
|||
- "[anonymous,0,a]" |
|||
timestamp: '1623693268225555737' |
@ -0,0 +1,35 @@ |
|||
{ |
|||
"inputs" : [ |
|||
{ |
|||
"ZX3hz85Vayc3Nhfs43ADhTeJXkDJ3fnXtfRiDW4pQzYRQ" : "5" |
|||
} |
|||
], |
|||
"message" : "This is an other example for transaction", |
|||
"nonce" : "3976914969180171529", |
|||
"outputs" : [ |
|||
{ |
|||
"Z24zaLMH6SCfAoC8ndS9XunjrkVpZW5tprhrZdSq3CcXWQ" : "3" |
|||
}, |
|||
{ |
|||
"Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq" : "2" |
|||
} |
|||
], |
|||
"pow" : "3976914969180292365", |
|||
"signatures" : [ |
|||
{ |
|||
"michelc" : [ |
|||
"ZHjX1cinn46FbTioY43qo2ZmfgnjZzXKRMiVN3tZRbxkzg61hNdKRoGptqeFa2tT5kzHqrSUTNcHFTfsLYSz5eDRGXmL3wzc1Gt", |
|||
"2021-06-14 19.54.28", |
|||
"[michelc,0,a]" |
|||
] |
|||
}, |
|||
{ |
|||
"anonymous" : [ |
|||
"ZHjX1cin92axvE1YtoPZyakN1HSFZmXpFxqSVqaWz1S3eyVA5rxTohXUcjcR5sPG9apfTEy34dSUyMPPuN2ngQNDMEFrEgZqbMN", |
|||
"2021-06-14 19.54.28", |
|||
"[anonymous,0,a]" |
|||
] |
|||
} |
|||
], |
|||
"timestamp" : "1623693268225555737" |
|||
} |
@ -0,0 +1,17 @@ |
|||
--- |
|||
message: approved 100 coins transaction for blocks mined by Florence M. Buzick for Luke S. Didyk |
|||
timestamp: '1626168575783464960' |
|||
inputs: |
|||
- coinbase: 100 |
|||
nonce: '7717044746294770303' |
|||
outputs: |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 100 |
|||
- miner: 0 |
|||
pow: '7717044746294792842' |
|||
signatures: |
|||
- coinbase: |
|||
- Zan1RjQUyrJ3JizN1nERKLNWukKB11QMuFEEV6LrdQtYLPncesNz26jdgp1WfM5Ky2DTgJZHwVpFkem39Z846F2rjKwwcMRC4h |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: |
|||
- Z381YwxUem1mcUiuBAuXevAJ8zaWhHRL9uCsx1Qix21gbSSpszfnwF1qVCxsPCHj7HPeLetVpKJaok3UH3gQ72AEXfTbmqcEW |
|||
- miner: |
|||
- ZHjX1cinqAEpNp7wUuX6P2jXWzZFRGQvuCtG78bVRv6w3hrXU2xihQKBDnniee4yA5sRzbxUZgqnzvzQfJsUQCzUf7T9xUDisF6 |
@ -1,11 +1,16 @@ |
|||
--- |
|||
message: This is a coinbase transaction of 100 coins to be distributed to Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq |
|||
inputs: |
|||
- coinbase: 100 |
|||
outputs: |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 100 |
|||
timestamp: '1625385951347499858' |
|||
- |
|||
coinbase: 100 |
|||
message: This is a coinbase transaction of 100 coins to be distributed to Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq |
|||
nonce: '3976914969180171529' |
|||
outputs: |
|||
- |
|||
Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 100 |
|||
pow: '3976914969180292365' |
|||
signatures: |
|||
- coinbase: ~ |
|||
- |
|||
coinbase: |
|||
- Z381YwyamFBjdvLNZCUcfoTqNQpxBzCznG9yaYsdFSztN4z9ZEyGDvpjnY33nq91WdjYk6zMuuUDdtvw5nxo6MYKVHcxPYGMJ |
|||
- 2021-07-07 22.49.00 |
|||
timestamp: '1625385951347499858' |
@ -1,9 +1,9 @@ |
|||
--- |
|||
message: This is an exemple of transaction with 3 coins going to Trina M. and 2 coins to Michel C. |
|||
--- # Example of Transaction of the ToyChain |
|||
message: This is an example of transaction with 3 coins going to Trina M. and 2 coins to Michel C. |
|||
timestamp: '1623693268225555737' |
|||
nonce: '3976914969180171529' |
|||
inputs: |
|||
- ZX3hz85Vayc3Nhfs43ADhTeJXkDJ3fnXtfRiDW4pQzYRQ: 3 |
|||
- ZX3hz85Vayc3Nhfs43ADhTeJXkDJ3fnXtfRiDW4pQzYRQ: 6 |
|||
outputs: |
|||
- Z24zaLMH6SCfAoC8ndS9XunjrkVpZW5tprhrZdSq3CcXWQ: 3 |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 2 |
@ -0,0 +1,2 @@ |
|||
--- |
|||
... |
@ -0,0 +1,19 @@ |
|||
--- |
|||
inputs: |
|||
- ZX3hz85Vayc3Nhfs43ADhTeJXkDJ3fnXtfRiDW4pQzYRQ: 8 |
|||
message: This is an exemple of transaction with 3 coins going to Trina M. and 2 coins to Michel C. |
|||
nonce: '3976914969180171529' |
|||
outputs: |
|||
- Z24zaLMH6SCfAoC8ndS9XunjrkVpZW5tprhrZdSq3CcXWQ: 3 |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 2 |
|||
pow: '3976914969180879919' |
|||
signatures: |
|||
- michelc: |
|||
- ZHjX1cinn46FbTioY43qo2ZmfgnjZzXKRMiVN3tZRbxkzg61hNdKRoGptqeFa2tT5kzHqrSUTNcHFTfsLYSz5eDRGXmL3wzc1Gt |
|||
- 2021-06-14 19.54.28 |
|||
- "[michelc,0,a]" |
|||
- anonymous: |
|||
- ZHjX1cin92axvE1YtoPZyakN1HSFZmXpFxqSVqaWz1S3eyVA5rxTohXUcjcR5sPG9apfTEy34dSUyMPPuN2ngQNDMEFrEgZqbMN |
|||
- 2021-06-14 19.54.28 |
|||
- "[anonymous,0,a]" |
|||
timestamp: '1623693268225555737' |
@ -0,0 +1 @@ |
|||
{"txaddr":"ZCBtx7Wg59hvMogWDchKVcGUMo68qDe2dkRfzaskAh3G","outputs":[{"Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq":"100"},{"miner":"0"}],"message":"agreed to give 100 for coinbase transaction to Z21G...stq","nonce":"7717044746241858558","inputs":[{"coinbase":"100"}],"timestamp":"1625714463012468224","signatures":[{"coinbase":["ZHjX1cinHZFWDANGjhJtVn9QMcj4Ra1ejfcZCoccEpLBstEKXD2cvV3b1pP2kC4uhr4BS5g7sARoXarh2C9MyD2e2hpCCvgNYMx"]},{"Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq":["Zan1RjVTEjuzF4fi8FPrWxnsnba6p8co5Kcwob6DWoxFU17cuSNQMogKqfhE5WNFgPu1aD77kLcYkBaHoBh4QNq8NPtpMVkHCx"]},{"miner":["Z381YwxKfWGTkTz8iC7NFxD3wCXwRNWBPeyoGxBVTprpbKP8fC48e4b31i9mcjcrsdVJvon91rUtXZBDv9C1KcvthF5oX4v86"]}],"pow":"7717044746294553205"} |
@ -0,0 +1,18 @@ |
|||
--- |
|||
txaddr: ZCBtx7Wg59hvMogWDchKVcGUMo68qDe2dkRfzaskAh3G |
|||
message: agreed to give 100 for coinbase transaction to Z21G...stq |
|||
timestamp: '1625714463012468224' |
|||
inputs: |
|||
- coinbase: 100 |
|||
outputs: |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 100 |
|||
- miner: 0 |
|||
nonce: '7717044746241858558' |
|||
pow: '7717044746294553205' |
|||
signatures: |
|||
- coinbase: |
|||
- ZHjX1cinHZFWDANGjhJtVn9QMcj4Ra1ejfcZCoccEpLBstEKXD2cvV3b1pP2kC4uhr4BS5g7sARoXarh2C9MyD2e2hpCCvgNYMx |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: |
|||
- Zan1RjVTEjuzF4fi8FPrWxnsnba6p8co5Kcwob6DWoxFU17cuSNQMogKqfhE5WNFgPu1aD77kLcYkBaHoBh4QNq8NPtpMVkHCx |
|||
- miner: |
|||
- Z381YwxKfWGTkTz8iC7NFxD3wCXwRNWBPeyoGxBVTprpbKP8fC48e4b31i9mcjcrsdVJvon91rUtXZBDv9C1KcvthF5oX4v86 |
@ -1,11 +0,0 @@ |
|||
--- |
|||
timestamp: '1623683269225552702' |
|||
inputs: |
|||
- coinbase: 50 |
|||
nonce: '3976914969180171529' |
|||
outputs: |
|||
- Z21GdiEggiGa7TPNaqGY8coBy97LoRNpPVu9fxig75nstq: 50 |
|||
message: This is a coinbase transaction of 50 coins for the genesis block |
|||
pow: '3976914969180292365' |
|||
signatures: |
|||
- coinbase: Zan1RjVTw7GPVyd7aygjWSrGCtX3M8CVRu3NAyqLC8MToNPE93ju4RrFFjunnbeTYnudR2gSKCamK82xjEfWEtGzGvTRDw25MG |
Write
Preview
Loading…
Cancel
Save
Reference in new issue