Ecoer Logo
VOTING POWER100.00%
DOWNVOTE POWER100.00%
RESOURCE CREDITS100.00%
REPUTATION PROGRESS90.37%
Net Worth
1.500USD
STEEM
0.001STEEM
SBD
2.962SBD
Effective Power
5.007SP
├── Own SP
1.347SP
└── Incoming Deleg
+3.659SP

Detailed Balance

STEEM
balance
0.001STEEM
market_balance
0.000STEEM
savings_balance
0.000STEEM
reward_steem_balance
0.000STEEM
STEEM POWER
Own SP
1.347SP
Delegated Out
0.000SP
Delegation In
3.659SP
Effective Power
5.007SP
Reward SP (pending)
0.000SP
SBD
sbd_balance
2.962SBD
sbd_conversions
0.000SBD
sbd_market_balance
0.000SBD
savings_sbd_balance
0.000SBD
reward_sbd_balance
0.000SBD
{
  "balance": "0.001 STEEM",
  "savings_balance": "0.000 STEEM",
  "reward_steem_balance": "0.000 STEEM",
  "vesting_shares": "2191.754397 VESTS",
  "delegated_vesting_shares": "0.000000 VESTS",
  "received_vesting_shares": "5951.905409 VESTS",
  "sbd_balance": "2.962 SBD",
  "savings_sbd_balance": "0.000 SBD",
  "reward_sbd_balance": "0.000 SBD",
  "conversions": []
}

Account Info

namedustvoice
id558356
rank730,467
reputation12601023545
created2018-01-04T12:06:27
recovery_accountsteem
proxyNone
post_count20
comment_count0
lifetime_vote_count0
witnesses_voted_for0
last_post2018-01-06T14:03:00
last_root_post2018-01-06T04:02:15
last_vote_time2018-01-13T22:02:54
proxied_vsf_votes0, 0, 0, 0
can_vote1
voting_power0
delayed_votes0
balance0.001 STEEM
savings_balance0.000 STEEM
sbd_balance2.962 SBD
savings_sbd_balance0.000 SBD
vesting_shares2191.754397 VESTS
delegated_vesting_shares0.000000 VESTS
received_vesting_shares5951.905409 VESTS
reward_vesting_balance0.000000 VESTS
vesting_balance0.000 STEEM
vesting_withdraw_rate0.000000 VESTS
next_vesting_withdrawal1969-12-31T23:59:59
withdrawn0
to_withdraw0
withdraw_routes0
savings_withdraw_requests0
last_account_recovery1970-01-01T00:00:00
reset_accountnull
last_owner_update1970-01-01T00:00:00
last_account_update2021-02-01T02:10:00
minedNo
sbd_seconds0
sbd_last_interest_payment2018-01-13T22:00:54
savings_sbd_last_interest_payment1970-01-01T00:00:00
{
  "active": {
    "account_auths": [],
    "key_auths": [
      [
        "STM8fVSCYFindrWfyACRBjd3e6LRthpKDG47KPrw6n3Tg2zK3yG21",
        1
      ]
    ],
    "weight_threshold": 1
  },
  "balance": "0.001 STEEM",
  "can_vote": true,
  "comment_count": 0,
  "created": "2018-01-04T12:06:27",
  "curation_rewards": 4,
  "delegated_vesting_shares": "0.000000 VESTS",
  "downvote_manabar": {
    "current_mana": 2035914951,
    "last_update_time": 1779061515
  },
  "guest_bloggers": [],
  "id": 558356,
  "json_metadata": "{\"profile\":{\"profile_image\":\"https://s14.postimg.org/a0f3n4az5/Dust_Voice.png\",\"cover_image\":\"https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500\",\"name\":\"DustVoice\",\"website\":\"http://dustvoice.de\"}}",
  "last_account_recovery": "1970-01-01T00:00:00",
  "last_account_update": "2021-02-01T02:10:00",
  "last_owner_update": "1970-01-01T00:00:00",
  "last_post": "2018-01-06T14:03:00",
  "last_root_post": "2018-01-06T04:02:15",
  "last_vote_time": "2018-01-13T22:02:54",
  "lifetime_vote_count": 0,
  "market_history": [],
  "memo_key": "STM69fmSxgcza1TYkcSgtWYPvnKvuaWoDBovN7bq7vvyHYCubJ2z4",
  "mined": false,
  "name": "dustvoice",
  "next_vesting_withdrawal": "1969-12-31T23:59:59",
  "other_history": [],
  "owner": {
    "account_auths": [],
    "key_auths": [
      [
        "STM73fjp31DVRWU9tynHwLsQYYFqBfsB76iEdpJSFhSJsVTuKab49",
        1
      ]
    ],
    "weight_threshold": 1
  },
  "pending_claimed_accounts": 0,
  "post_bandwidth": 0,
  "post_count": 20,
  "post_history": [],
  "posting": {
    "account_auths": [
      [
        "dmania.app",
        1
      ]
    ],
    "key_auths": [
      [
        "STM5XZRiDa7pe2QwkytkGamYZ1TtzBgKxDoWeDjVzP1oySuD9gLrK",
        1
      ]
    ],
    "weight_threshold": 1
  },
  "posting_json_metadata": "{\"profile\":{\"profile_image\":\"https://cdn.steemitimages.com/DQmYdjT45r1aPnK4Cigvc5LK6Wjo1SDuhGS8LUb8YfzvwSa/crop_image.jpg\",\"cover_image\":\"https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500\",\"name\":\"DustVoice\",\"website\":\"https://dustvoice.de\",\"version\":2}}",
  "posting_rewards": 1132,
  "proxied_vsf_votes": [
    0,
    0,
    0,
    0
  ],
  "proxy": "",
  "received_vesting_shares": "5951.905409 VESTS",
  "recovery_account": "steem",
  "reputation": "12601023545",
  "reset_account": "null",
  "reward_sbd_balance": "0.000 SBD",
  "reward_steem_balance": "0.000 STEEM",
  "reward_vesting_balance": "0.000000 VESTS",
  "reward_vesting_steem": "0.000 STEEM",
  "savings_balance": "0.000 STEEM",
  "savings_sbd_balance": "0.000 SBD",
  "savings_sbd_last_interest_payment": "1970-01-01T00:00:00",
  "savings_sbd_seconds": "0",
  "savings_sbd_seconds_last_update": "1970-01-01T00:00:00",
  "savings_withdraw_requests": 0,
  "sbd_balance": "2.962 SBD",
  "sbd_last_interest_payment": "2018-01-13T22:00:54",
  "sbd_seconds": "0",
  "sbd_seconds_last_update": "2018-01-13T22:00:54",
  "tags_usage": [],
  "to_withdraw": 0,
  "transfer_history": [],
  "vesting_balance": "0.000 STEEM",
  "vesting_shares": "2191.754397 VESTS",
  "vesting_withdraw_rate": "0.000000 VESTS",
  "vote_history": [],
  "voting_manabar": {
    "current_mana": "8143659806",
    "last_update_time": 1779061515
  },
  "voting_power": 0,
  "withdraw_routes": 0,
  "withdrawn": 0,
  "witness_votes": [],
  "witnesses_voted_for": 0,
  "rank": 730467
}

Withdraw Routes

IncomingOutgoing
Empty
Empty
{
  "incoming": [],
  "outgoing": []
}
From Date
To Date
steemdelegated 3.659 SP to @dustvoice
2026/05/17 23:45:15
delegateedustvoice
delegatorsteem
vesting shares5951.905409 VESTS
Transaction InfoBlock #106142852/Trx e6f53cdcad6281a6a5342f553a33f164af944800
View Raw JSON Data
{
  "block": 106142852,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "5951.905409 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2026-05-17T23:45:15",
  "trx_id": "e6f53cdcad6281a6a5342f553a33f164af944800",
  "trx_in_block": 0,
  "virtual_op": 0
}
steemdelegated 1.992 SP to @dustvoice
2026/05/12 01:48:39
delegateedustvoice
delegatorsteem
vesting shares3239.695004 VESTS
Transaction InfoBlock #105973277/Trx b07295ca5d8895d56be8e8802a08056bfdb91162
View Raw JSON Data
{
  "block": 105973277,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "3239.695004 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2026-05-12T01:48:39",
  "trx_id": "b07295ca5d8895d56be8e8802a08056bfdb91162",
  "trx_in_block": 2,
  "virtual_op": 0
}
steemdelegated 3.667 SP to @dustvoice
2026/04/25 23:06:57
delegateedustvoice
delegatorsteem
vesting shares5964.421165 VESTS
Transaction InfoBlock #105510517/Trx 3fcaf3de454891f62921b90c13959ffc36f02200
View Raw JSON Data
{
  "block": 105510517,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "5964.421165 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2026-04-25T23:06:57",
  "trx_id": "3fcaf3de454891f62921b90c13959ffc36f02200",
  "trx_in_block": 2,
  "virtual_op": 0
}
steemdelegated 2.017 SP to @dustvoice
2026/01/23 06:26:54
delegateedustvoice
delegatorsteem
vesting shares3281.241823 VESTS
Transaction InfoBlock #102850187/Trx c6c938104d6ea8fc3a179e8cda47d31c776ac8c8
View Raw JSON Data
{
  "block": 102850187,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "3281.241823 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2026-01-23T06:26:54",
  "trx_id": "c6c938104d6ea8fc3a179e8cda47d31c776ac8c8",
  "trx_in_block": 0,
  "virtual_op": 0
}
steemdelegated 2.118 SP to @dustvoice
2024/12/17 01:46:27
delegateedustvoice
delegatorsteem
vesting shares3445.461020 VESTS
Transaction InfoBlock #91296607/Trx 4f9884de465d692095b67ee5d6c793d468b3688f
View Raw JSON Data
{
  "block": 91296607,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "3445.461020 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2024-12-17T01:46:27",
  "trx_id": "4f9884de465d692095b67ee5d6c793d468b3688f",
  "trx_in_block": 9,
  "virtual_op": 0
}
steemdelegated 2.222 SP to @dustvoice
2023/11/13 17:29:21
delegateedustvoice
delegatorsteem
vesting shares3614.594552 VESTS
Transaction InfoBlock #79850814/Trx 0117fdaf0a9dc98b98de6de42af5bb262298088c
View Raw JSON Data
{
  "block": 79850814,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "3614.594552 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2023-11-13T17:29:21",
  "trx_id": "0117fdaf0a9dc98b98de6de42af5bb262298088c",
  "trx_in_block": 9,
  "virtual_op": 0
}
steemdelegated 4.028 SP to @dustvoice
2023/09/21 21:14:12
delegateedustvoice
delegatorsteem
vesting shares6551.873338 VESTS
Transaction InfoBlock #78347117/Trx 3679a1e8fdccd462ca8077dab0cb68c575386254
View Raw JSON Data
{
  "block": 78347117,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "6551.873338 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2023-09-21T21:14:12",
  "trx_id": "3679a1e8fdccd462ca8077dab0cb68c575386254",
  "trx_in_block": 1,
  "virtual_op": 0
}
steemdelegated 4.164 SP to @dustvoice
2022/11/03 11:06:42
delegateedustvoice
delegatorsteem
vesting shares6773.554776 VESTS
Transaction InfoBlock #69112556/Trx fadca8e11a560c68a258d2f3e7b555e3b5d91358
View Raw JSON Data
{
  "block": 69112556,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "6773.554776 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2022-11-03T11:06:42",
  "trx_id": "fadca8e11a560c68a258d2f3e7b555e3b5d91358",
  "trx_in_block": 2,
  "virtual_op": 0
}
steemdelegated 4.300 SP to @dustvoice
2022/01/17 10:25:30
delegateedustvoice
delegatorsteem
vesting shares6994.088007 VESTS
Transaction InfoBlock #60808779/Trx 39df0674bfdceeca8450580a198f28d90dfa57c3
View Raw JSON Data
{
  "block": 60808779,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "6994.088007 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2022-01-17T10:25:30",
  "trx_id": "39df0674bfdceeca8450580a198f28d90dfa57c3",
  "trx_in_block": 17,
  "virtual_op": 0
}
steemdelegated 4.413 SP to @dustvoice
2021/06/14 00:22:03
delegateedustvoice
delegatorsteem
vesting shares7177.856665 VESTS
Transaction InfoBlock #54607192/Trx 6e0f374a21b04e0f2226ae962d7be57d83b26682
View Raw JSON Data
{
  "block": 54607192,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "7177.856665 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2021-06-14T00:22:03",
  "trx_id": "6e0f374a21b04e0f2226ae962d7be57d83b26682",
  "trx_in_block": 1,
  "virtual_op": 0
}
dustvoicecustom json: notify
2021/02/01 02:12:51
idnotify
json["setLastRead",{"date":"2021-02-01T02:12:47"}]
required auths[]
required posting auths["dustvoice"]
Transaction InfoBlock #50823756/Trx fa34491940b0f3a70fe324bc532092240d686b5b
View Raw JSON Data
{
  "block": 50823756,
  "op": [
    "custom_json",
    {
      "id": "notify",
      "json": "[\"setLastRead\",{\"date\":\"2021-02-01T02:12:47\"}]",
      "required_auths": [],
      "required_posting_auths": [
        "dustvoice"
      ]
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2021-02-01T02:12:51",
  "trx_id": "fa34491940b0f3a70fe324bc532092240d686b5b",
  "trx_in_block": 5,
  "virtual_op": 0
}
dustvoiceupdated their account properties
2021/02/01 02:10:00
accountdustvoice
extensions[]
json metadata
posting json metadata{"profile":{"profile_image":"https://cdn.steemitimages.com/DQmYdjT45r1aPnK4Cigvc5LK6Wjo1SDuhGS8LUb8YfzvwSa/crop_image.jpg","cover_image":"https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500","name":"DustVoice","website":"https://dustvoice.de","version":2}}
Transaction InfoBlock #50823699/Trx 81b49d6c706614abf1f83056c39381205e8a97e0
View Raw JSON Data
{
  "block": 50823699,
  "op": [
    "account_update2",
    {
      "account": "dustvoice",
      "extensions": [],
      "json_metadata": "",
      "posting_json_metadata": "{\"profile\":{\"profile_image\":\"https://cdn.steemitimages.com/DQmYdjT45r1aPnK4Cigvc5LK6Wjo1SDuhGS8LUb8YfzvwSa/crop_image.jpg\",\"cover_image\":\"https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500\",\"name\":\"DustVoice\",\"website\":\"https://dustvoice.de\",\"version\":2}}"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2021-02-01T02:10:00",
  "trx_id": "81b49d6c706614abf1f83056c39381205e8a97e0",
  "trx_in_block": 5,
  "virtual_op": 0
}
steemdelegated 4.528 SP to @dustvoice
2020/12/11 10:41:54
delegateedustvoice
delegatorsteem
vesting shares7365.278639 VESTS
Transaction InfoBlock #49354678/Trx 19e081b2eeb081f8520c8ac67aad1b1c6ad19645
View Raw JSON Data
{
  "block": 49354678,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "7365.278639 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-12-11T10:41:54",
  "trx_id": "19e081b2eeb081f8520c8ac67aad1b1c6ad19645",
  "trx_in_block": 1,
  "virtual_op": 0
}
steemdelegated 1.176 SP to @dustvoice
2020/12/06 04:19:12
delegateedustvoice
delegatorsteem
vesting shares1912.543513 VESTS
Transaction InfoBlock #49206243/Trx ff43e619c63f899cea75c896507968a2b491e144
View Raw JSON Data
{
  "block": 49206243,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "1912.543513 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-12-06T04:19:12",
  "trx_id": "ff43e619c63f899cea75c896507968a2b491e144",
  "trx_in_block": 5,
  "virtual_op": 0
}
steemdelegated 4.532 SP to @dustvoice
2020/12/05 14:20:06
delegateedustvoice
delegatorsteem
vesting shares7371.486493 VESTS
Transaction InfoBlock #49189775/Trx dae8708cffd94888576bfd0defd90ace70301ee2
View Raw JSON Data
{
  "block": 49189775,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "7371.486493 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-12-05T14:20:06",
  "trx_id": "dae8708cffd94888576bfd0defd90ace70301ee2",
  "trx_in_block": 6,
  "virtual_op": 0
}
steemdelegated 1.180 SP to @dustvoice
2020/11/02 14:39:42
delegateedustvoice
delegatorsteem
vesting shares1920.017158 VESTS
Transaction InfoBlock #48256647/Trx 5491cee36dd8af5b316876d6f1fe0ed736fdd0d4
View Raw JSON Data
{
  "block": 48256647,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "1920.017158 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-11-02T14:39:42",
  "trx_id": "5491cee36dd8af5b316876d6f1fe0ed736fdd0d4",
  "trx_in_block": 7,
  "virtual_op": 0
}
steemdelegated 4.657 SP to @dustvoice
2020/05/09 05:15:51
delegateedustvoice
delegatorsteem
vesting shares7574.291852 VESTS
Transaction InfoBlock #43216479/Trx c02f6a696c6c9694a0fff9eb30009589cc07847f
View Raw JSON Data
{
  "block": 43216479,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "7574.291852 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-05-09T05:15:51",
  "trx_id": "c02f6a696c6c9694a0fff9eb30009589cc07847f",
  "trx_in_block": 1,
  "virtual_op": 0
}
steemdelegated 1.201 SP to @dustvoice
2020/05/08 08:47:36
delegateedustvoice
delegatorsteem
vesting shares1953.311140 VESTS
Transaction InfoBlock #43192490/Trx 60bdaca8aef0310b247d4c2242390e662c80ac21
View Raw JSON Data
{
  "block": 43192490,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "1953.311140 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-05-08T08:47:36",
  "trx_id": "60bdaca8aef0310b247d4c2242390e662c80ac21",
  "trx_in_block": 6,
  "virtual_op": 0
}
steemdelegated 4.665 SP to @dustvoice
2020/04/15 21:19:27
delegateedustvoice
delegatorsteem
vesting shares7587.269271 VESTS
Transaction InfoBlock #42562220/Trx caaae21e5874fd5d01f175161f0533c5326fce08
View Raw JSON Data
{
  "block": 42562220,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "7587.269271 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-04-15T21:19:27",
  "trx_id": "caaae21e5874fd5d01f175161f0533c5326fce08",
  "trx_in_block": 22,
  "virtual_op": 0
}
2020/01/04 13:51:36
authorsteemitboard
bodyCongratulations @dustvoice! You received a personal award! <table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@dustvoice/birthday2.png</td><td>Happy Birthday! - You are on the Steem blockchain for 2 years!</td></tr></table> <sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@dustvoice) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=dustvoice)_</sub> ###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!
json metadata{"image":["https://steemitboard.com/img/notify.png"]}
parent authordustvoice
parent permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
permlinksteemitboard-notify-dustvoice-20200104t135136000z
title
Transaction InfoBlock #39635180/Trx 9a7b3433e3362d5bf603c7a04465fb82fdd48c39
View Raw JSON Data
{
  "block": 39635180,
  "op": [
    "comment",
    {
      "author": "steemitboard",
      "body": "Congratulations @dustvoice! You received a personal award!\n\n<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@dustvoice/birthday2.png</td><td>Happy Birthday! - You are on the Steem blockchain for 2 years!</td></tr></table>\n\n<sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@dustvoice) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=dustvoice)_</sub>\n\n\n###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!",
      "json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}",
      "parent_author": "dustvoice",
      "parent_permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "permlink": "steemitboard-notify-dustvoice-20200104t135136000z",
      "title": ""
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2020-01-04T13:51:36",
  "trx_id": "9a7b3433e3362d5bf603c7a04465fb82fdd48c39",
  "trx_in_block": 8,
  "virtual_op": 0
}
dtubesent 0.001 STEEM to @dustvoice- "Time is running out, claim your DTube account now before anyone else can! Login at https://d.tube"
2019/08/22 17:59:30
amount0.001 STEEM
fromdtube
memoTime is running out, claim your DTube account now before anyone else can! Login at https://d.tube
todustvoice
Transaction InfoBlock #35781598/Trx c6f647834c61455c82daf631a85ad5f590517480
View Raw JSON Data
{
  "block": 35781598,
  "op": [
    "transfer",
    {
      "amount": "0.001 STEEM",
      "from": "dtube",
      "memo": "Time is running out, claim your DTube account now before anyone else can! Login at https://d.tube",
      "to": "dustvoice"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2019-08-22T17:59:30",
  "trx_id": "c6f647834c61455c82daf631a85ad5f590517480",
  "trx_in_block": 11,
  "virtual_op": 0
}
steemdelegated 4.785 SP to @dustvoice
2019/05/12 14:34:18
delegateedustvoice
delegatorsteem
vesting shares7782.892076 VESTS
Transaction InfoBlock #32845089/Trx 874bcdc926dd30fab093d87649cf57104f1c10b7
View Raw JSON Data
{
  "block": 32845089,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "7782.892076 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2019-05-12T14:34:18",
  "trx_id": "874bcdc926dd30fab093d87649cf57104f1c10b7",
  "trx_in_block": 6,
  "virtual_op": 0
}
2019/01/04 13:53:45
authorsteemitboard
bodyCongratulations @dustvoice! You received a personal award! <table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@dustvoice/birthday1.png</td><td>1 Year on Steemit</td></tr></table> <sub>_[Click here to view your Board](https://steemitboard.com/@dustvoice)_</sub> > Support [SteemitBoard's project](https://steemit.com/@steemitboard)! **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!
json metadata{"image":["https://steemitboard.com/img/notify.png"]}
parent authordustvoice
parent permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
permlinksteemitboard-notify-dustvoice-20190104t135344000z
title
Transaction InfoBlock #29162119/Trx a87ffaf0266e58521a28820ac7c18a60a37a56ca
View Raw JSON Data
{
  "block": 29162119,
  "op": [
    "comment",
    {
      "author": "steemitboard",
      "body": "Congratulations @dustvoice! You received a personal award!\n\n<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@dustvoice/birthday1.png</td><td>1 Year on Steemit</td></tr></table>\n\n<sub>_[Click here to view your Board](https://steemitboard.com/@dustvoice)_</sub>\n\n\n> Support [SteemitBoard's project](https://steemit.com/@steemitboard)! **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!",
      "json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}",
      "parent_author": "dustvoice",
      "parent_permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "permlink": "steemitboard-notify-dustvoice-20190104t135344000z",
      "title": ""
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2019-01-04T13:53:45",
  "trx_id": "a87ffaf0266e58521a28820ac7c18a60a37a56ca",
  "trx_in_block": 5,
  "virtual_op": 0
}
steemdelegated 4.907 SP to @dustvoice
2018/05/16 20:15:12
delegateedustvoice
delegatorsteem
vesting shares7982.444511 VESTS
Transaction InfoBlock #22489805/Trx 0519b80efe28d5b3ba83c5e8497bcbab8f6d4e82
View Raw JSON Data
{
  "block": 22489805,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "7982.444511 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-05-16T20:15:12",
  "trx_id": "0519b80efe28d5b3ba83c5e8497bcbab8f6d4e82",
  "trx_in_block": 16,
  "virtual_op": 0
}
2018/02/17 11:06:30
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voteronurgule
weight10000 (100.00%)
Transaction InfoBlock #19946996/Trx e74ed24ce26bfc7c977e73cd79cd637e8655e660
View Raw JSON Data
{
  "block": 19946996,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "onurgule",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-02-17T11:06:30",
  "trx_id": "e74ed24ce26bfc7c977e73cd79cd637e8655e660",
  "trx_in_block": 34,
  "virtual_op": 0
}
steemdelegated 17.538 SP to @dustvoice
2018/01/13 23:45:42
delegateedustvoice
delegatorsteem
vesting shares28526.330483 VESTS
Transaction InfoBlock #18955189/Trx 810fa5d2198648ffbc8fa5ce152bb27f5e6f2d6c
View Raw JSON Data
{
  "block": 18955189,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "28526.330483 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-13T23:45:42",
  "trx_id": "810fa5d2198648ffbc8fa5ce152bb27f5e6f2d6c",
  "trx_in_block": 74,
  "virtual_op": 0
}
2018/01/13 22:02:54
authorresteemator
permlinkresteemator-reached-500-followers
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18953133/Trx ed4edcfe0c5b883b2442a051c45611accafd3edc
View Raw JSON Data
{
  "block": 18953133,
  "op": [
    "vote",
    {
      "author": "resteemator",
      "permlink": "resteemator-reached-500-followers",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-13T22:02:54",
  "trx_id": "ed4edcfe0c5b883b2442a051c45611accafd3edc",
  "trx_in_block": 53,
  "virtual_op": 0
}
2018/01/13 22:02:51
idfollow
json["follow",{"follower":"dustvoice","following":"resteemator","what":["blog"]}]
required auths[]
required posting auths["dustvoice"]
Transaction InfoBlock #18953132/Trx 0fce0701cb53cb765daee9c053bea79a8aaf5b5b
View Raw JSON Data
{
  "block": 18953132,
  "op": [
    "custom_json",
    {
      "id": "follow",
      "json": "[\"follow\",{\"follower\":\"dustvoice\",\"following\":\"resteemator\",\"what\":[\"blog\"]}]",
      "required_auths": [],
      "required_posting_auths": [
        "dustvoice"
      ]
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-13T22:02:51",
  "trx_id": "0fce0701cb53cb765daee9c053bea79a8aaf5b5b",
  "trx_in_block": 47,
  "virtual_op": 0
}
2018/01/13 22:02:30
authordustvoice
permlinkre-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t140259089z
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18953125/Trx fb2fff2ceded00f53b06c8e3753ff3c258767c94
View Raw JSON Data
{
  "block": 18953125,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "re-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t140259089z",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-13T22:02:30",
  "trx_id": "fb2fff2ceded00f53b06c8e3753ff3c258767c94",
  "trx_in_block": 20,
  "virtual_op": 0
}
dustvoiceclaimed reward balance: 2.886 SBD, 0.696 SP
2018/01/13 22:00:54
accountdustvoice
reward sbd2.886 SBD
reward steem0.000 STEEM
reward vests1132.522840 VESTS
Transaction InfoBlock #18953093/Trx f251ab9f502aee28fef5476460ec88bf8955e500
View Raw JSON Data
{
  "block": 18953093,
  "op": [
    "claim_reward_balance",
    {
      "account": "dustvoice",
      "reward_sbd": "2.886 SBD",
      "reward_steem": "0.000 STEEM",
      "reward_vests": "1132.522840 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-13T22:00:54",
  "trx_id": "f251ab9f502aee28fef5476460ec88bf8955e500",
  "trx_in_block": 41,
  "virtual_op": 0
}
2018/01/13 04:02:15
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
sbd payout2.886 SBD
steem payout0.000 STEEM
vesting payout1132.522840 VESTS
Transaction InfoBlock #18931552/Virtual Operation #41
View Raw JSON Data
{
  "block": 18931552,
  "op": [
    "author_reward",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "sbd_payout": "2.886 SBD",
      "steem_payout": "0.000 STEEM",
      "vesting_payout": "1132.522840 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-13T04:02:15",
  "trx_id": "0000000000000000000000000000000000000000",
  "trx_in_block": 4294967295,
  "virtual_op": 41
}
dustvoiceclaimed reward balance: 0.076 SBD, 0.021 SP
2018/01/13 00:00:09
accountdustvoice
reward sbd0.076 SBD
reward steem0.000 STEEM
reward vests34.818087 VESTS
Transaction InfoBlock #18926719/Trx eacee19de396a66f17af5ba262310a57c10ad536
View Raw JSON Data
{
  "block": 18926719,
  "op": [
    "claim_reward_balance",
    {
      "account": "dustvoice",
      "reward_sbd": "0.076 SBD",
      "reward_steem": "0.000 STEEM",
      "reward_vests": "34.818087 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-13T00:00:09",
  "trx_id": "eacee19de396a66f17af5ba262310a57c10ad536",
  "trx_in_block": 3,
  "virtual_op": 0
}
dustvoiceupvoted (100.00%) @cephalopod / 45-kb
2018/01/12 23:58:39
authorcephalopod
permlink45-kb
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926689/Trx e1d4e04e7c6e9701cd87ec7262232dd7cece3dc4
View Raw JSON Data
{
  "block": 18926689,
  "op": [
    "vote",
    {
      "author": "cephalopod",
      "permlink": "45-kb",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:58:39",
  "trx_id": "e1d4e04e7c6e9701cd87ec7262232dd7cece3dc4",
  "trx_in_block": 18,
  "virtual_op": 0
}
2018/01/12 23:58:36
authorplanet-rium
permlinkcity-wanders-series-watercolour-made-by-me-planet-rium
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926688/Trx 88e65a42c0b2f5f86768f63737f77d4535e62eb8
View Raw JSON Data
{
  "block": 18926688,
  "op": [
    "vote",
    {
      "author": "planet-rium",
      "permlink": "city-wanders-series-watercolour-made-by-me-planet-rium",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:58:36",
  "trx_id": "88e65a42c0b2f5f86768f63737f77d4535e62eb8",
  "trx_in_block": 26,
  "virtual_op": 0
}
dustvoiceupvoted (100.00%) @onyemacourage / egghsej5
2018/01/12 23:57:57
authoronyemacourage
permlinkegghsej5
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926675/Trx dda7ce91183102744d9f5204fa732a8b8733dbab
View Raw JSON Data
{
  "block": 18926675,
  "op": [
    "vote",
    {
      "author": "onyemacourage",
      "permlink": "egghsej5",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:57",
  "trx_id": "dda7ce91183102744d9f5204fa732a8b8733dbab",
  "trx_in_block": 17,
  "virtual_op": 0
}
2018/01/12 23:57:51
authortheaustrianguy
permlinkgnejloye
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926673/Trx 992423ad31dd0606b32e7f6d5ba39604df6111f7
View Raw JSON Data
{
  "block": 18926673,
  "op": [
    "vote",
    {
      "author": "theaustrianguy",
      "permlink": "gnejloye",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:51",
  "trx_id": "992423ad31dd0606b32e7f6d5ba39604df6111f7",
  "trx_in_block": 5,
  "virtual_op": 0
}
2018/01/12 23:57:48
authornashbe
permlinksteem-and-steem-dollars-midnight-update
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926672/Trx f3873725acbb6aba527409bf00b1eee586788727
View Raw JSON Data
{
  "block": 18926672,
  "op": [
    "vote",
    {
      "author": "nashbe",
      "permlink": "steem-and-steem-dollars-midnight-update",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:48",
  "trx_id": "f3873725acbb6aba527409bf00b1eee586788727",
  "trx_in_block": 19,
  "virtual_op": 0
}
2018/01/12 23:57:45
authordhruv120511
permlinkwhat-will-earth-and-humans-look-like-in-1-000-years
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926671/Trx 4c6a6f8d319279e73ee48c8d776f90b14242553c
View Raw JSON Data
{
  "block": 18926671,
  "op": [
    "vote",
    {
      "author": "dhruv120511",
      "permlink": "what-will-earth-and-humans-look-like-in-1-000-years",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:45",
  "trx_id": "4c6a6f8d319279e73ee48c8d776f90b14242553c",
  "trx_in_block": 33,
  "virtual_op": 0
}
2018/01/12 23:57:39
authorbrandt
permlinkone-day-black-and-white-challenge-day-1
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926669/Trx a2daaa3c277ee2d81189c8db7a99c986573e489d
View Raw JSON Data
{
  "block": 18926669,
  "op": [
    "vote",
    {
      "author": "brandt",
      "permlink": "one-day-black-and-white-challenge-day-1",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:39",
  "trx_id": "a2daaa3c277ee2d81189c8db7a99c986573e489d",
  "trx_in_block": 32,
  "virtual_op": 0
}
2018/01/12 23:57:36
authorleohira123
permlinkdaily-landscape-shot-the-beautiful-crops-c467d37c5ef5
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926668/Trx 973e901ca1a0afb04bb907b6d974de6cc74be5b1
View Raw JSON Data
{
  "block": 18926668,
  "op": [
    "vote",
    {
      "author": "leohira123",
      "permlink": "daily-landscape-shot-the-beautiful-crops-c467d37c5ef5",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:36",
  "trx_id": "973e901ca1a0afb04bb907b6d974de6cc74be5b1",
  "trx_in_block": 49,
  "virtual_op": 0
}
2018/01/12 23:57:33
authorledjo1991
permlinkcryptocurrency-exchanges-need-smarter-faster-and-more-secure-id-verification-with-velix-id
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926667/Trx 53397db0f729eda5f581465891a756d3af574a7d
View Raw JSON Data
{
  "block": 18926667,
  "op": [
    "vote",
    {
      "author": "ledjo1991",
      "permlink": "cryptocurrency-exchanges-need-smarter-faster-and-more-secure-id-verification-with-velix-id",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:33",
  "trx_id": "53397db0f729eda5f581465891a756d3af574a7d",
  "trx_in_block": 26,
  "virtual_op": 0
}
2018/01/12 23:57:30
authorevernoticethat
permlinka-thank-you-message-to-my-500-amazing-followers
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18926666/Trx 95beb29eb10bb4129f1f6ea3853da8aa9049db74
View Raw JSON Data
{
  "block": 18926666,
  "op": [
    "vote",
    {
      "author": "evernoticethat",
      "permlink": "a-thank-you-message-to-my-500-amazing-followers",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T23:57:30",
  "trx_id": "95beb29eb10bb4129f1f6ea3853da8aa9049db74",
  "trx_in_block": 17,
  "virtual_op": 0
}
2018/01/12 02:51:30
authorwbjadventures
bodyReally nice
json metadata{"app":"dtube/0.6"}
parent authordustvoice
parent permlinkh8p9o8ul
permlinky6u2mff2l
titley6u2mff2l
Transaction InfoBlock #18901399/Trx c0e05cc35f6b80bca690ddb00f7ca2adf179547c
View Raw JSON Data
{
  "block": 18901399,
  "op": [
    "comment",
    {
      "author": "wbjadventures",
      "body": "Really nice ",
      "json_metadata": "{\"app\":\"dtube/0.6\"}",
      "parent_author": "dustvoice",
      "parent_permlink": "h8p9o8ul",
      "permlink": "y6u2mff2l",
      "title": "y6u2mff2l"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-12T02:51:30",
  "trx_id": "c0e05cc35f6b80bca690ddb00f7ca2adf179547c",
  "trx_in_block": 5,
  "virtual_op": 0
}
framegamesupvoted (100.00%) @dustvoice / h8p9o8ul
2018/01/11 22:48:21
authordustvoice
permlinkh8p9o8ul
voterframegames
weight10000 (100.00%)
Transaction InfoBlock #18896538/Trx e6f03066eb5be5e074089070ef83bf63209b9639
View Raw JSON Data
{
  "block": 18896538,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "h8p9o8ul",
      "voter": "framegames",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T22:48:21",
  "trx_id": "e6f03066eb5be5e074089070ef83bf63209b9639",
  "trx_in_block": 34,
  "virtual_op": 0
}
2018/01/11 16:10:45
authordustvoice
permlinkh8p9o8ul
voterabdulrehman8833
weight10000 (100.00%)
Transaction InfoBlock #18888587/Trx 04812bd80ca73dd574f00b0602a61d69cca6cf59
View Raw JSON Data
{
  "block": 18888587,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "h8p9o8ul",
      "voter": "abdulrehman8833",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T16:10:45",
  "trx_id": "04812bd80ca73dd574f00b0602a61d69cca6cf59",
  "trx_in_block": 47,
  "virtual_op": 0
}
2018/01/11 16:10:45
authordustvoice
permlinkh8p9o8ul
voterabdulrehman8833
weight10000 (100.00%)
Transaction InfoBlock #18888587/Trx 5c8b836ec9151c58a024648d5bba80e0c0499a2a
View Raw JSON Data
{
  "block": 18888587,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "h8p9o8ul",
      "voter": "abdulrehman8833",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T16:10:45",
  "trx_id": "5c8b836ec9151c58a024648d5bba80e0c0499a2a",
  "trx_in_block": 32,
  "virtual_op": 0
}
2018/01/11 15:35:18
authorstopyoutube
bodyI gave you some lovin! How 'bout you give me some too?
json metadata{"app":"dtube/0.6"}
parent authordustvoice
parent permlinkh8p9o8ul
permlinky6i4o69ri
titley6i4o69ri
Transaction InfoBlock #18887878/Trx 25c9d8ed284ad539592f3950198a3245f9f3a56a
View Raw JSON Data
{
  "block": 18887878,
  "op": [
    "comment",
    {
      "author": "stopyoutube",
      "body": "I gave you some lovin! How 'bout you give me some too?",
      "json_metadata": "{\"app\":\"dtube/0.6\"}",
      "parent_author": "dustvoice",
      "parent_permlink": "h8p9o8ul",
      "permlink": "y6i4o69ri",
      "title": "y6i4o69ri"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T15:35:18",
  "trx_id": "25c9d8ed284ad539592f3950198a3245f9f3a56a",
  "trx_in_block": 52,
  "virtual_op": 0
}
2018/01/11 13:36:06
authordustvoice
permlinkre-abhishek77-photography-201814t1942933z-20180104t133603927z
sbd payout0.053 SBD
steem payout0.000 STEEM
vesting payout18.433100 VESTS
Transaction InfoBlock #18885494/Virtual Operation #16
View Raw JSON Data
{
  "block": 18885494,
  "op": [
    "author_reward",
    {
      "author": "dustvoice",
      "permlink": "re-abhishek77-photography-201814t1942933z-20180104t133603927z",
      "sbd_payout": "0.053 SBD",
      "steem_payout": "0.000 STEEM",
      "vesting_payout": "18.433100 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T13:36:06",
  "trx_id": "0000000000000000000000000000000000000000",
  "trx_in_block": 4294967295,
  "virtual_op": 16
}
2018/01/11 13:30:54
authordustvoice
permlinkre-givemeyoursteem-the-8-secrets-of-the-happiest-people-20180104t133051960z
sbd payout0.023 SBD
steem payout0.000 STEEM
vesting payout8.192490 VESTS
Transaction InfoBlock #18885390/Virtual Operation #13
View Raw JSON Data
{
  "block": 18885390,
  "op": [
    "author_reward",
    {
      "author": "dustvoice",
      "permlink": "re-givemeyoursteem-the-8-secrets-of-the-happiest-people-20180104t133051960z",
      "sbd_payout": "0.023 SBD",
      "steem_payout": "0.000 STEEM",
      "vesting_payout": "8.192490 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T13:30:54",
  "trx_id": "0000000000000000000000000000000000000000",
  "trx_in_block": 4294967295,
  "virtual_op": 13
}
2018/01/11 13:11:51
comment authortamsguitar
comment permlinkhandycam-photography-euro-trip-random-pics-in-an-around-london-part-i
curatordustvoice
reward6.144372 VESTS
Transaction InfoBlock #18885009/Virtual Operation #16
View Raw JSON Data
{
  "block": 18885009,
  "op": [
    "curation_reward",
    {
      "comment_author": "tamsguitar",
      "comment_permlink": "handycam-photography-euro-trip-random-pics-in-an-around-london-part-i",
      "curator": "dustvoice",
      "reward": "6.144372 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T13:11:51",
  "trx_id": "0000000000000000000000000000000000000000",
  "trx_in_block": 4294967295,
  "virtual_op": 16
}
dustvoicereceived 0.001 SP curation reward for @izweed / mistakes-were-made-zg1hbmlh-gftdt
2018/01/11 12:56:30
comment authorizweed
comment permlinkmistakes-were-made-zg1hbmlh-gftdt
curatordustvoice
reward2.048125 VESTS
Transaction InfoBlock #18884702/Virtual Operation #25
View Raw JSON Data
{
  "block": 18884702,
  "op": [
    "curation_reward",
    {
      "comment_author": "izweed",
      "comment_permlink": "mistakes-were-made-zg1hbmlh-gftdt",
      "curator": "dustvoice",
      "reward": "2.048125 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-11T12:56:30",
  "trx_id": "0000000000000000000000000000000000000000",
  "trx_in_block": 4294967295,
  "virtual_op": 25
}
steemdelegated 18.259 SP to @dustvoice
2018/01/08 19:33:09
delegateedustvoice
delegatorsteem
vesting shares29700.586530 VESTS
Transaction InfoBlock #18806285/Trx d7d322078df3778ae70e1c6676da8f511c7830b7
View Raw JSON Data
{
  "block": 18806285,
  "op": [
    "delegate_vesting_shares",
    {
      "delegatee": "dustvoice",
      "delegator": "steem",
      "vesting_shares": "29700.586530 VESTS"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-08T19:33:09",
  "trx_id": "d7d322078df3778ae70e1c6676da8f511c7830b7",
  "trx_in_block": 10,
  "virtual_op": 0
}
2018/01/08 04:45:06
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voterdana-edwards
weight8555 (85.55%)
Transaction InfoBlock #18788562/Trx 0346fc94746fd922ef2548c1688634a6acc6eb80
View Raw JSON Data
{
  "block": 18788562,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "dana-edwards",
      "weight": 8555
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-08T04:45:06",
  "trx_id": "0346fc94746fd922ef2548c1688634a6acc6eb80",
  "trx_in_block": 5,
  "virtual_op": 0
}
2018/01/07 18:17:12
authordhruv123
permlinkwhat-steem-price-is-it-a-new-year-gift-do-you-here-a-new-site-just-like-steemit
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18776010/Trx d6725e941aeab5d2807ccc901b50a069d16f00f6
View Raw JSON Data
{
  "block": 18776010,
  "op": [
    "vote",
    {
      "author": "dhruv123",
      "permlink": "what-steem-price-is-it-a-new-year-gift-do-you-here-a-new-site-just-like-steemit",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:17:12",
  "trx_id": "d6725e941aeab5d2807ccc901b50a069d16f00f6",
  "trx_in_block": 0,
  "virtual_op": 0
}
2018/01/07 18:16:51
authordobartim
permlinkcompetition-for-the-best-yoga-move-the-prize-is-10-sbd-7-days-day-7-the-registration-is-in-progress-last-call-24-hour
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18776003/Trx 6094bbef962839d39bcc75b248aff8de291de50f
View Raw JSON Data
{
  "block": 18776003,
  "op": [
    "vote",
    {
      "author": "dobartim",
      "permlink": "competition-for-the-best-yoga-move-the-prize-is-10-sbd-7-days-day-7-the-registration-is-in-progress-last-call-24-hour",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:16:51",
  "trx_id": "6094bbef962839d39bcc75b248aff8de291de50f",
  "trx_in_block": 17,
  "virtual_op": 0
}
2018/01/07 18:16:45
authormedicbtom
permlink64exjn-crypto-trades-for-the-day
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18776001/Trx 7ab788a256704c044c413bf1698fd370e1570d03
View Raw JSON Data
{
  "block": 18776001,
  "op": [
    "vote",
    {
      "author": "medicbtom",
      "permlink": "64exjn-crypto-trades-for-the-day",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:16:45",
  "trx_id": "7ab788a256704c044c413bf1698fd370e1570d03",
  "trx_in_block": 0,
  "virtual_op": 0
}
2018/01/07 18:16:33
authoralamin0263
permlinkboys-will-understand-zg1hbmlh-9y01q
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18775997/Trx 762e2f87522c15a6c407145027f4e2e9e89d8528
View Raw JSON Data
{
  "block": 18775997,
  "op": [
    "vote",
    {
      "author": "alamin0263",
      "permlink": "boys-will-understand-zg1hbmlh-9y01q",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:16:33",
  "trx_id": "762e2f87522c15a6c407145027f4e2e9e89d8528",
  "trx_in_block": 7,
  "virtual_op": 0
}
dustvoiceupvoted (100.00%) @yuriks2000 / 9lesriuc
2018/01/07 18:16:30
authoryuriks2000
permlink9lesriuc
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18775996/Trx c483f74e87a7ac010ebd1986dbe05bad2bbdaafe
View Raw JSON Data
{
  "block": 18775996,
  "op": [
    "vote",
    {
      "author": "yuriks2000",
      "permlink": "9lesriuc",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:16:30",
  "trx_id": "c483f74e87a7ac010ebd1986dbe05bad2bbdaafe",
  "trx_in_block": 6,
  "virtual_op": 0
}
2018/01/07 18:16:24
authorfloprime
permlinkhappy-new-year
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18775994/Trx c60d3a929128df5f708389d8d53400c168392924
View Raw JSON Data
{
  "block": 18775994,
  "op": [
    "vote",
    {
      "author": "floprime",
      "permlink": "happy-new-year",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:16:24",
  "trx_id": "c60d3a929128df5f708389d8d53400c168392924",
  "trx_in_block": 2,
  "virtual_op": 0
}
2018/01/07 18:16:15
authordana-edwards
permlinkend-game-regulation-the-us-government-will-eventually-demand-require-having-a-license-to-use-cryptocurrency
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18775991/Trx 945f05e550d12bffbd9b8d7eb54a5cd42aa0b788
View Raw JSON Data
{
  "block": 18775991,
  "op": [
    "vote",
    {
      "author": "dana-edwards",
      "permlink": "end-game-regulation-the-us-government-will-eventually-demand-require-having-a-license-to-use-cryptocurrency",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:16:15",
  "trx_id": "945f05e550d12bffbd9b8d7eb54a5cd42aa0b788",
  "trx_in_block": 49,
  "virtual_op": 0
}
2018/01/07 18:16:09
authorclanbwarclan
permlinkthey-are-multiplying
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18775989/Trx a3f56661c57c81d7f5fbb3a855790424a073a358
View Raw JSON Data
{
  "block": 18775989,
  "op": [
    "vote",
    {
      "author": "clanbwarclan",
      "permlink": "they-are-multiplying",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:16:09",
  "trx_id": "a3f56661c57c81d7f5fbb3a855790424a073a358",
  "trx_in_block": 38,
  "virtual_op": 0
}
2018/01/07 18:15:36
authorjout
permlinkgerman-short-film-english-subtitles-about-people-taking-pictures-of-an-accident-with-a-cruel-twist
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18775978/Trx 6f897f7e80791b8fd2ada3d92513ba62b51e596a
View Raw JSON Data
{
  "block": 18775978,
  "op": [
    "vote",
    {
      "author": "jout",
      "permlink": "german-short-film-english-subtitles-about-people-taking-pictures-of-an-accident-with-a-cruel-twist",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:15:36",
  "trx_id": "6f897f7e80791b8fd2ada3d92513ba62b51e596a",
  "trx_in_block": 44,
  "virtual_op": 0
}
2018/01/07 18:15:18
authorvm2904
permlinkhow-to-have-fantastic-memory-part-1-original-wildlife-photographs-and-thoughts
voterdustvoice
weight10000 (100.00%)
Transaction InfoBlock #18775972/Trx 544bb11a21a23632ba51e89004a1bdbb74fad94b
View Raw JSON Data
{
  "block": 18775972,
  "op": [
    "vote",
    {
      "author": "vm2904",
      "permlink": "how-to-have-fantastic-memory-part-1-original-wildlife-photographs-and-thoughts",
      "voter": "dustvoice",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-07T18:15:18",
  "trx_id": "544bb11a21a23632ba51e89004a1bdbb74fad94b",
  "trx_in_block": 44,
  "virtual_op": 0
}
2018/01/06 17:34:51
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voterudin06
weight10000 (100.00%)
Transaction InfoBlock #18746404/Trx 6058c4a457bce2bafc9dc3fba3421aaa97fb01da
View Raw JSON Data
{
  "block": 18746404,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "udin06",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T17:34:51",
  "trx_id": "6058c4a457bce2bafc9dc3fba3421aaa97fb01da",
  "trx_in_block": 70,
  "virtual_op": 0
}
2018/01/06 16:29:36
authorhursh
bodyDone
json metadata{"tags":["resteem"],"app":"steemit/0.1"}
parent authordustvoice
parent permlinkre-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t140259089z
permlinkre-dustvoice-re-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t162900741z
title
Transaction InfoBlock #18745099/Trx 4109d2dc7433d359327ba602e3db0e2520adf628
View Raw JSON Data
{
  "block": 18745099,
  "op": [
    "comment",
    {
      "author": "hursh",
      "body": "Done",
      "json_metadata": "{\"tags\":[\"resteem\"],\"app\":\"steemit/0.1\"}",
      "parent_author": "dustvoice",
      "parent_permlink": "re-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t140259089z",
      "permlink": "re-dustvoice-re-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t162900741z",
      "title": ""
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T16:29:36",
  "trx_id": "4109d2dc7433d359327ba602e3db0e2520adf628",
  "trx_in_block": 31,
  "virtual_op": 0
}
2018/01/06 14:43:51
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voteromrusman
weight10000 (100.00%)
Transaction InfoBlock #18742985/Trx fe1d4e2ca395163217c26db850d0484b728a2bd6
View Raw JSON Data
{
  "block": 18742985,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "omrusman",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T14:43:51",
  "trx_id": "fe1d4e2ca395163217c26db850d0484b728a2bd6",
  "trx_in_block": 6,
  "virtual_op": 0
}
2018/01/06 14:08:57
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voterubg
weight100 (1.00%)
Transaction InfoBlock #18742288/Trx f44d23503800a21e2d4de4a3781a8cfbdb17d9a0
View Raw JSON Data
{
  "block": 18742288,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "ubg",
      "weight": 100
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T14:08:57",
  "trx_id": "f44d23503800a21e2d4de4a3781a8cfbdb17d9a0",
  "trx_in_block": 15,
  "virtual_op": 0
}
2018/01/06 14:08:54
authordustvoice
body# What exactly is a blockchain? - How does a blockchain work? - What is Bitcoin or STEEM exactly? - How does a blockchain make sure of its correctness - What is **mining** exactly? **These are only some questions, probably many of you are asking yourselves. I'm here to provide you with kind of an unusual answer. My goal is to help you undestand the whole system behind blockchains, by actually creating a small blockchain yourself!** With the rise of cryptocurrencies and decentralized systems like Bitcoin or STEEM, many people want to really undestand, what this is all about. I will show you how the system works, by coding a blockchain from scratch in python with you. The guide will be mainly for Windows, but I will also add comments regarding Linux. You don't know a whole of python, to follow this guide, but it is advised to know the most basic basics. # Get ready ## Setup Python and pip First off, we need to install Python 3.6+ along with pip, with which you can install python packages. - On **Linux**, you can install python, by simply typing `sudo apt-get install python3.6` into the terminal. If you encounter errors, please try `sudo apt-get update` and then try to execute the command again. If it still doesn't work, please search for installation instructions for your specific system on your preferred search engine. - On **Windows**, 1. first download the binary, that suits your system best, under the [official python download page for windows.](https://www.python.org/downloads/windows/). Make sure you grab at least the _version 3.6_ or higher. 2. Install the file you just downloaded. Make sure you check the option to install pip, when provided with an option to do so. If not, don't worry, it probably is enabled by default. ## IDE or not? As a next step, you want to decide, whether to utilize an [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) or not. An IDE is an environment, which supports you in the creation process of your application, by providing many features, with for example syntax highlighting, or code completion, to name just 2 possible features. My favorite IDE for Python development is probably PyCharm, which you can fetch from [this link.](https://www.jetbrains.com/pycharm) Setting up PyCharm on Windows is as simple, as downloading the executable installer and installing it with the provided setup utility. PyCharm is free tu use, as long as you use the Community Edition. You can also use your coding notepad of choice. We will only work in one file, which you have to execute, so as long as your text-editing software is able to produce files with the ending `.py`, it will work fine. ## Setup your workspace (PyCharm) If you decided to use PyCharm, simply open it up and click on _Create Project_ in the popup dialogue. In the next dialogue you want to specify your project's name. I chose to use _MyBlockChain_ as my project name. Finally click on _create_ in the bottom right corner. On your left hand side, you're now provided with a file tree. 1. Right-Click on the folder which consists of your project's name, in my case _MyBlockChain_ 2. Go to _new_ 3. Finally click on _Python File_ and 4. Define a Filename. I chose `MyBlockChain.py` as my filename. ## Create your file (Simple Text Editor) If you use a simple text editor, just create a file anywhere you like with the file extension `.py`. In my case I chose to use the filename `MyBlockChain.py`. ## Install the needed packages ### PyCharm In PyCharm you can install packages very easily and add them to your project: 1. Make sure, you have your project open 2. Go to _File_ -> _Settings_ -> _Project: [your project name]_ -> _Project Interpreter_ 3. Then click on the green plus symbol. 4. In the search field type in _Flask_ first. Select the first entry, which simply says _Flask_. Then click on Install Package in the bottom left corner. 5. Do the same thing for _Requests_. ### Pip If you chose not to use PyCharm, you simply need to open up the terminal on linux or the command prompt, or PowerShell on Windows _(simply press **Windows+R** and type in cmd)_ and then execute `pip install Flask==0.12.2 requests==2.18.4 `. If this gives you an error, please double check that you have _pip_ installed. If the problem still occurs, please troubleshoot the error message using google, as there are too many possibilities, what the error could be caused by, for me to discuss every one of them here. ## Getting a HTTP-Client You will also need a HTTP-Client, as we need to make `GET` and `POST` requests to our Flask instance, at some Point in time. Mainly, there are two options - [_Postman_](https://www.getpostman.com/) or [_cURL_](https://curl.haxx.se/). I highly recommend _Postman_, as it is easy and intuitive to use, but if you just want a simple and quick solution, without having to register for an account, just use _cURL_. Online solutions, probably won't work, as the webserver you are going to be trying to access, is just on your local machine. ## Just gimme the source code! If you just want the source code and don't want to follow my instructions, please scroll down, to the very end of this post, where I will add the source code in its complete beauty. # The Blockchain - Your Blockchain ## Step 1: Creating a simplistic Blockchain A block chain is basically a chain of blocks that are linked together in some way, as you have already figured. In this case, every block contains a hash of the previous block. A hash is a hexadecimal number that is determined by a specific algorithm. Imagine a hash being a digital fingerprint of an item. A good hash algorithm will never return the same hash for two different items, so every hash is individual. In our case we will be using the [_SHA-256_](https://en.wikipedia.org/wiki/SHA-2) algorithm. Furthermore the hash algorithm is not reversible, so you can't determine the object, by having its hash, but you can always apply the hash algorithm on the object, to get its hash. As every item has the hash of its previous item, the blockchain is protected against violation, as one would have to change every following block, as the hash changes with every change, as two different items can't have the same hash. ### The Blockchain class Our Blockchain class basically consists of a constructor and some functions. In the constructor, we will create two empty lists - one to store our blockchain in and another, for our transactions. As for now, our class will have several functions: - A function to create new blocks - A function to create new transactions - A function, which hashes a block - A function to fetch the last block The python template looks like this: ```python class MyBlockChain(object): def __init__(self): self.blockchain = [] self.transactions = [] def create_new_block(self): # This function creates a new block and appends it to the chain pass def create_new_transaction(self): # This function creates a new transaction and adds it to the list of transactions pass @staticmethod def hash(block): # This method hashes the passed block pass @property def last_block(self): # This function returns the last block in the chain pass ``` ## Step 2: The blocks As described earlier, a blockchain consists of blocks. So I will cover them first. Each Block has 5 fields: - An index, - an Unix timestamp, - a list of transactions, - a proof, - and finally the hash of the previous block. Just to clarify things, here is an example of a block ```json example_block = { 'index': 5, 'timestamp': 1515110045.123456, 'transactions': [ { 'sender': "154d8554f9541e12354e1234f512a001", 'recipient': "8654e21254c6512a51bce156542d1e5c", 'amount': 212, } ], 'proof': 488612354568, 'previous_hash': "c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e" } ``` ## Step 3: Hashing it As every block needs the hash of the previous block, we need a function, that calculates the hash of a block. To accomplish this, we simply modify our empty `hash` function ```python import hashlib import json class MyBlockChain(object): [...] @staticmethod def hash(block): """ This function hashes the block using the SHA-256 hash algorithm The function is given a block and returns a string, consisting of the hash :param block: <dict> Block :return: <str> """ # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes block_sorted = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_sorted).hexdigest() ``` ## Step 4: Transactions Our `create_new_transaction` method is responsible for adding new transactions to the `transactions` list, which will then be stored inside a block. The whole function is pretty self explanatory. But first we need a function to return the last block of the chain, as we will calculate the new index, at which the transaction will be stored, by increasing the index of the last block by 1 ```python class MyBlockChain(object): [...] @property def last_block(self): return self.blockchain[-1] ``` Now we can fill out the `create_new_transaction` function ```python class MyBlockChain(object): [...] def create_new_transaction(self, sender, recipient, amount): """ This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions. :param sender: <str> Sender's address :param recipient: <str> Recipient's address :param amount: <int> Amount to be transferred :return: <int> This is the index of the block that will contain this transaction """ self.transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1 ``` ## Step 5: Creating new Blocks By now we almost have everything at our hands, what we need in order to make a new block. The only thing missing is the _proof_ field. As this is a little harder to understand, I will explain it later. But we still have one problem - if every block has the hash of the previous block, what shall we do with our first block, as there is no previous block for us to hash. This first block is called the _genesis_ block. ```python import hashlib import json from time import time class MyBlockChain(object): def __init__(self): self.blockchain = [] self.transactions = [] # Creation of the mentioned genesis block self.create_new_block(previous_hash=1, proof=100) def create_new_block(self, proof, previous_hash=None): """ Creates a new block and adds it to the blockchain :param proof: <int> This is generated by the proof of work algorithm :param previous_hash: (Optional) <str> Hash of the preleading Block :return: <dict> Return the new block """ new_block = { 'index': len(self.blockchain) + 1, 'timestamp': time(), 'transactions': self.transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.blockchain[-1]), } # As all pending transactions have been processed and added to the block, the list can be resetted self.transactions = [] # Add the new block to the blockchain self.blockchain.append(new_block) return new_block ``` ## Step 6: What's up with the proof?! ### The [Proof of Work (PoW) algorithm](https://en.wikipedia.org/wiki/Proof-of-work_system) This system wants to **proof** that work has been done. Now a little bit less abstract. Basically we are searching for a number that matches a specific criteria. The thing is, for the system to work, the process of finding a number matching the criteria has to be **difficult**, but the verification process has to be **quick and easy**. This is how new blocks are created, or expressed in another, more commonly used term, _mined_. #### Still too abstract? Ok here is an example: We are looking for a hash of a product of two integers that ends with a 1. So the result of the multiplication of `a` and `b` gets hashed and has to end with a 1. If we set a to `a` static value, our algorithm will determine a value for `b`, for which this criteria is matched. ```python from hashlib import sha256 a = 12 b = 0 # We don't know what b has to be. It will be determined by the algorithm while sha256(f'{a*b}'.encode()).hexdigest()[-1] != "1": b += 1 print(f'The solution is b = {b}') ``` This example outputs ``` The solution is b = 4 ``` This means that the hash of `12*4` ends with a 1 ``` hash(48) = 98010bd9270f9b100b6214a21754fd33bdc8d41b2bc9f9dd16ff54d3c34ffd71 ``` As you can tell, the verification process doesn't need countless loops, until it finds a matching pair. You just have to run the hash algorithm once on the numbers and you can easily determine, whether the numbers match the criteria, or not. ## Step 7: Implementing PoW Firstoff, we need a criteria, or commonly referred to as a rule. For now, our rule is that the hash has to have 5 leading zeroes, so `000005bc845e...` would be a valid result, but `000019ea76c4` would not. As the difficulty rises extremely, if we would require 6 leading zeros, the difficulty of our simple algorithm can be adjusted by changing the amount of leading zeroes required. This is the implementation in python: ```python [...] from uuid import uuid4 class MyBlockChain(object): [...] def pow(self, last_proof): """ Simple PoW Algorithm: - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof. :param last_proof: <int> :return: <int> """ current_proof = 0 while self.validate_proof(last_proof, current_proof) is False: current_proof += 1 return current_proof @staticmethod def validate_proof(last_proof, current_proof): """ Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes. :param last_proof: <int> Previous Proof Number :param current_proof: <int> Current Proof Number :return: <bool> """ possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest() return possible_hash[:5] == "00000" ``` ## Step 8: Interacting with our class Now we are able to create a blockchain. But we can't really interact with it, as we have only interacted with the functions and variables of our class. We are going to use HTTP requests to interact with our blockchain. So let's set it up! # HTTP in the house! To talk to our blockchain using Http requests, we need some help - which comes in the form of the _Flask Framework_. We will create and implement 3 basic methods for now: - `/blockchain` to retrieve the full blockchain - `/mining` to make our simple server mine a block - `/transactions/add` to add a new transaction to the blockchain. ## Step 9: Flask First we need to implement Flask. Here is the code: ```python [...] from textwrap import dedent from flask import Flask, jsonify, request class MyBlockChain(object): [...] app = Flask(__name__) node_identifier = str(uuid4()).replace('-', '') myblockchain = MyBlockChain() @app.route('/blockchain', methods=['GET']) def get_full_chain(): output = { 'chain': myblockchain.blockchain, 'length': len(myblockchain.blockchain), } return jsonify(output), 200 @app.route('/mining', methods=['GET']) def mining(): pass @app.route('/transactions/add', methods=['POST']) def add_transaction(): pass if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` ## Step 10: Adding Transactions As this is commonly the main task of a block chain and also required for a new block, I will cover this first. The user sends a _POST request_ to `/transactions/add` with a JSON object, containing all required fields. This is an example, for a possible, valid request: ```json { "sender": "154d8554f9541e12354e1234f512a001", "recipient": "8654e21254c6512a51bce156542d1e5c", "amount": 212 } ``` As you can see, a request has three fields: - A _sender_ field, with the sender id, - a _recipient_ field, with the recipient id - and an amount, which defines how many units are to be transferred Now we just need to implement this function ```python [...] @app.route('/transactions/add', methods=['POST']) def add_transaction(): values = request.get_json() # The POST request has to have the following required fields required = ['sender', 'recipient', 'amount'] if not all(k in values for k in required): return 'There are values missing', 400 # Adds a new transaction by utilizing our function index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount']) output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'} return jsonify(output), 201 ``` This function simply calls the `create_new_transaction` method with the parameters of the POST request ## Step 11: Setup your mines As discussed earlier, future blocks have to be mined. If a new block is found/mined, all pending transactions are added to this block. To 'mine' a new block, our function hast to do three things 1. Calculate the proof 2. Reward the miner with a specific amount of coins (in our example 1 coin) 3. Add the new mined block to the blockchain _(The fact that the recipient is our current node, will make more sense, as we will talk about decentralization later on.)_ ```python @app.route('/mining', methods=['GET']) def mining(): # Calculate the new proof by using our PoW algorithm last_block = myblockchain.last_block last_proof = last_block['proof'] proof = myblockchain.pow(last_proof) # For finding/mining the proof, the miner is granted a reward # The sender is nobody, as this coin is coming out of the void myblockchain.create_new_transaction( sender="0", recipient=node_identifier, amount=1, ) # Add the new created block to the chain previous_hash = myblockchain.hash(last_block) newblock = myblockchain.create_new_block(proof, previous_hash) output = { 'message': "A new block was mined", 'index': newblock['index'], 'transactions': newblock['transactions'], 'proof': newblock['proof'], 'previous_hash': newblock['previous_hash'], } return jsonify(output), 200 ``` # Hello World! Now, **finally** we will be interacting with our blockchain API. Grab your HTTP client of choice and get going! I will explain the procedure for Postman and cURL. ## Step 12: Start up the chain First off fire up your server. In PyCharm simply click on _Run_ -> _Run..._ and select _[your filename].py_ as the file to run, in my case _myblockchain.py_. If you chose to use a simple python file without an IDE, fire up a terminal or command prompt window inside the directory your file is located in and execute the following command ``` python blockchain.py ``` as a result you will see something similar to this ``` $ python blockchain.py * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) ``` **Note that you may be prompted with a dialogue of your firewall. Just accept it.** ## Step 13: Mining it all! Ok let's try the most exciting thing first, **mining**. I'm sure you can't wait to mine your first block, so let's do it! As you can see in the code ```python [...] @app.route('/mining', methods=['GET']) def mining(): [...] ``` we will be interacting with the `mining` part of our API through `GET` requests. This makes sense, as our only goal with this part of the API is, to mine a new block. We don't have to pass anything to the function at all, so a `GET` request is the way to go. ### Postman If you chose to use Postman, here is a quick tutorial on how to make a post request. 1. First you have to register for an account, if you haven't already done that 2. and login after that. 3. If you are logged in, you shoudl be provided with several options such as _Request_, _Collection_, _Environment_. 4. You could simply use the option _Request_, but to keep things organized, we are going to select the _Collection_ option. 5. After that simply choose a name for your collection, in my case I'm using _MyBlockChain_ as my name. 6. Now click on the _New_ Button, located in the top left corner and select _Request_ this time. We are now going to be creating 3 requests. 7. The first request is going to be our _mining_ request, second is a _new transaction_ request and finally we will have a _get whole blockchain_ request. Of course you can customize the request names as you like. 8. **Make sure, as you create these 3 requests, that you select our newly created Collection in the bottom section of the dialogue!** 9. Now click on our Collection's folder in the left sidebar. You should see your 3 newly created requests. Select the _mining_ request first. 10. On the right you are now provided with an interface. As you can see by the selected item from the dropdown box, left to the text field, a `GET` request is the standard request type, so we don't have to change that yet. 11. In the text field `Enter request URL` we are now going to enter the `mining` URL of our API, so enter `http://localhost:5000/mining` as the request URL. ### cURL If you chose to use cURL as your HTTP client, simply type `curl -i -H "Content-Type: application/json" -X GET http://localhost:5000/mining` in a terminal window ### Either way With both methods you should see something similar to this as a result ```json { "index": 2, "message": "New Block Forged", "previous_hash": "0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a", "proof": 888273, "transactions": [ { "amount": 1, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "0" } ] } ``` ## Step 14: Transactions are great! As our mining algorithm seems to be working fine, let's create a new transaction, to be stored in a fresh mined block. To do that in ### Postman 1. Click on the _new transaction_ request in the left sidebar. 2. Click on the _GET_ button with the small arrow pointing down. 3. Select _POST_ from the drop-down list. 4. In the navbar below the text field, select _Body_ 5. and then mark the _raw_ option. 6. You should now be provided with an editor like text area, and another drop-down menu next to the _binary_ option, where _Text_ is currently selected. Select _JSON (application/json)_ from this list. 7. Now type in the following into the text area. ```json { "sender": "your-node-address", "recipient": "another-node-address", "amount": 212 } ``` ### cURL Just execute `curl -X POST -H "Content-Type: application/json" -d '{"sender": "your-node-address", "recipient": "another-node-address", "amount": 212}' "http://localhost:5000/transactions/add"` in a terminal window. ### In both cases Replace `your-node-address` with the _recipient_ address from you mining request, as this is your node address. You can also select any other 32 digit hexadezimal number, for now. Furthermore replace `another-node-address` with a random 32 digit hexadezimal number for now, as we currently don't have any other nodes. Adjust the `amount` to your liking. And **voilà**! You have registered your first transaction! ## Step 15: The Chain... So let's inspect our chain! If you're using ### Postman Click on the _get whole blockchain_ request in the left sidebar and simply enter `http://localhost:5000/blockchain` in the `Enter request URL` text field, as _GET_ should be preselected. If not, please change it to the _GET_ option. ### cURL just execute `curl -i -H "Content-Type: application/json" -X GET http://localhost:5000/blockchain` in a terminal window. ### Either way you should get your whole blockchain in form of a JSON-Object. In my case, my blockchain looks like this, after mining 2 times, adding 3 transactions and mining another block: ```json { "chain": [ { "index": 1, "previous_hash": "1", "proof": 100, "timestamp": 1515156902.4502413, "transactions": [] }, { "index": 2, "previous_hash": "0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a", "proof": 888273, "timestamp": 1515156913.2686973, "transactions": [ { "amount": 1, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "0" } ] }, { "index": 3, "previous_hash": "1d2ae4a41f4a82ce6f04944e8227bf9c4d951d560f8763b910d7314634dfe09c", "proof": 1156297, "timestamp": 1515158367.3596537, "transactions": [ { "amount": 212, "recipient": "d4ee26eee15148ee92c6cd394edd974e", "sender": "491002ea048a42609d967027cc46a07b" }, { "amount": 212, "recipient": "5654c5654e1b551a65e15f5e4651c156", "sender": "491002ea048a42609d967027cc46a07b" }, { "amount": 111, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "5654c5654e1b551a65e15f5e4651c156" }, { "amount": 1, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "0" } ] } ], "length": 3 } ``` # Decentralizing it Ok, so we got a blockchain, that's working fine and we can interact with it. But one very important thing is still missing: **Decentralization**. This is a core element of the blockchain idea. First off by decentralizing the whole thing, safety and integrity of the blockchain is guaranteed, as a change in the blockchain will be recognized, by the other nodes, as they also have a copy of the blockchain, and discarded. The second reason is that we somehow have to make sense of our transactions. For this we need other nodes and why shouldn't they contribute to our network, by being a part of the blockchain system?! But we still have a conflict there: What if a node has a blockchain that differs from all the others? For our simple blockchain we will always make the **longest valid** blockchain authorative. ## Step 16: Someone out there?! But first things first. To get started, we first have to implement other nodes into our system. To accomplish this task, we have to adjust a few things in our API. First off, we are going to implement some new endpoints: 1. `/nodes/add` to add new nodes in form of a list of URLs 2. `/nodes/resolve` to resolve the conflict we discussed previously by using a consensus algorithm. To do this, we have to modify our Blockchain class first: ```python [...] from urllib.parse import urlparse class MyBlockChain(object): def __init__(self): [...] self.nodes = set() def add_node(self, address): """ Register a new node :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000' :return: None """ node_url = urlparse(address) self.nodes.add(node_url.netloc) ``` ## Step 17: We need Consensus To resolve the conflict of differing blockchains between the nodes, we are going to implement a consensus algorithm. As we discussed earlier, we are always utilizing the longest valid blockchain. First we are implementing a function that validates a blockchain: ```python [...] import requests class MyBlockChain(object) [...] def validate_blockchain(self, test_chain): """ Evaluate, whether a blockchain is valid :param chain: <list> The blockchain that shall be tested :return: <bool> Returns true if the blockchain is valid """ last_block = test_chain[0] current_index = 1 while current_index < len(test_chain): block = test_chain[current_index] # Determine, whether the hash is correct if block['previous_hash'] != self.hash(last_block): return False # Determine, wheter the proof of work is correct if not self.validate_proof(last_block['proof'], block['proof']): return False last_block = block current_index += 1 return True ``` Now we just have to run every blockchain in our surrounding network through this consensus algorithm: ```python [...] class MyBlockChain(object) [...] def resolve(self): """ This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously. :return: <bool> Returns true, if our chain was substituted with an updated version """ surrounding_nodes = self.nodes updated_chain = None # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain max_length = len(self.blockchain) # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain. for node_iterator in surrounding_nodes: response = requests.get(f'http://{node_iterator}/blockchain') if response.status_code == 200: length = response.json()['length'] chain_iterator = response.json()['chain'] if length > max_length and self.validate_blockchain(chain_iterator): max_length = length updated_chain = chain_iterator # If we found a new blockchain, replace our current blockchain with the new one if updated_chain: self.blockchain = updated_chain return True return False ``` Now we just have to register our new functions as new endpoints in the API: ```python @app.route('/nodes/add', methods=['POST']) def add_nodes(): values = request.get_json() nodes = values.get('nodes') if nodes is None: return "You didn't post a valid list of nodes. Please double check your input!", 400 for node in nodes: myblockchain.add_node(node) response = { 'message': 'All of your specified nodes have been added to the network!', 'total_nodes': list(myblockchain.nodes), } return jsonify(response), 201 @app.route('/nodes/resolve', methods=['GET']) def consensus(): replaced = myblockchain.resolve() if replaced: response = { 'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.', 'new_chain': myblockchain.blockchain } else: response = { 'message': 'The blockchain of this node is already the longest valid chain within the network.', 'chain': myblockchain.blockchain } return jsonify(response), 200 ``` ## Step 18: Friends are great. Even if they're virtual... To test our decentralization algorithms, either grab some friends, to run some nodes for you, or just run the same program on different ports, so you would have to start up an instance of our blockchain-program, then change to port to 5001 for example, save, fire up an instance of this _modified_ program, change the port to 5002, etc. ## Step 19: Add them to your friends list If you got some instances, you just have to register them. To do this, simply send a `POST` request with the following content ```json { "nodes": ["http://[ip-of-another-node-or-127.0.0.1-for-your-local-machine]:[the-port-number]"] } ``` to `http://[the-node-ip-you-want-to-register-it-to]:[port]/nodes/add` ## Step 20: Consensus check After that try to mine some blocks and even add some transactions on let's say node 2 and then run `http://[a-node-ip]:[port]/nodes/resolve` on let's say node 1. The consensus algorithm should step into action and update the blockchain of node 1. # The whole thang I keep my promises ```python import hashlib import json import requests from time import time from uuid import uuid4 from textwrap import dedent from flask import Flask, jsonify, request from urllib.parse import urlparse class MyBlockChain(object): def __init__(self): self.blockchain = [] self.transactions = [] # Creation of the mentioned genesis block self.create_new_block(previous_hash=1, proof=100) self.nodes = set() def create_new_block(self, proof, previous_hash=None): """ Creates a new block and adds it to the blockchain :param proof: <int> This is generated by the proof of work algorithm :param previous_hash: (Optional) <str> Hash of the preleading Block :return: <dict> Return the new block """ new_block = { 'index': len(self.blockchain) + 1, 'timestamp': time(), 'transactions': self.transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.blockchain[-1]), } # As all pending transactions have been processed and added to the block, the list can be resetted self.transactions = [] # Add the new block to the blockchain self.blockchain.append(new_block) return new_block def create_new_transaction(self, sender, recipient, amount): """ This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions. :param sender: <str> Sender's address :param recipient: <str> Recipient's address :param amount: <int> Amount to be transferred :return: <int> This is the index of the block that will contain this transaction """ self.transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1 @staticmethod def hash(block): """ This function hashes the block using the SHA-256 hash algorithm The function is given a block and returns a string, consisting of the hash :param block: <dict> Block :return: <str> """ # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes block_sorted = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_sorted).hexdigest() @property def last_block(self): return self.blockchain[-1] def pow(self, last_proof): """ Simple PoW Algorithm: - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof. :param last_proof: <int> :return: <int> """ current_proof = 0 while self.validate_proof(last_proof, current_proof) is False: current_proof += 1 return current_proof @staticmethod def validate_proof(last_proof, current_proof): """ Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes. :param last_proof: <int> Previous Proof Number :param current_proof: <int> Current Proof Number :return: <bool> """ possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest() return possible_hash[:5] == "00000" def add_node(self, address): """ Register a new node :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000' :return: None """ node_url = urlparse(address) self.nodes.add(node_url.netloc) def validate_blockchain(self, test_chain): """ Evaluate, whether a blockchain is valid :param chain: <list> The blockchain that shall be tested :return: <bool> Returns true if the blockchain is valid """ last_block = test_chain[0] current_index = 1 while current_index < len(test_chain): block = test_chain[current_index] # Determine, whether the hash is correct if block['previous_hash'] != self.hash(last_block): return False # Determine, wheter the proof of work is correct if not self.validate_proof(last_block['proof'], block['proof']): return False last_block = block current_index += 1 return True def resolve(self): """ This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously. :return: <bool> Returns true, if our chain was substituted with an updated version """ surrounding_nodes = self.nodes updated_chain = None # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain max_length = len(self.blockchain) # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain. for node_iterator in surrounding_nodes: response = requests.get(f'http://{node_iterator}/blockchain') if response.status_code == 200: length = response.json()['length'] chain_iterator = response.json()['chain'] if length > max_length and self.validate_blockchain(chain_iterator): max_length = length updated_chain = chain_iterator # If we found a new blockchain, replace our current blockchain with the new one if updated_chain: self.blockchain = updated_chain return True return False app = Flask(__name__) node_identifier = str(uuid4()).replace('-', '') myblockchain = MyBlockChain() @app.route('/blockchain', methods=['GET']) def get_full_chain(): output = { 'chain': myblockchain.blockchain, 'length': len(myblockchain.blockchain), } return jsonify(output), 200 @app.route('/mining', methods=['GET']) def mining(): # Calculate the new proof by using our PoW algorithm last_block = myblockchain.last_block last_proof = last_block['proof'] proof = myblockchain.pow(last_proof) # For finding/mining the proof, the miner is granted a reward # The sender is nobody, as this coin is coming out of the void myblockchain.create_new_transaction( sender="0", recipient=node_identifier, amount=1, ) # Add the new created block to the chain previous_hash = myblockchain.hash(last_block) newblock = myblockchain.create_new_block(proof, previous_hash) output = { 'message': "A new block was mined", 'index': newblock['index'], 'transactions': newblock['transactions'], 'proof': newblock['proof'], 'previous_hash': newblock['previous_hash'], } return jsonify(output), 200 @app.route('/transactions/add', methods=['POST']) def add_transaction(): values = request.get_json() # The POST request has to have the following required fields required = ['sender', 'recipient', 'amount'] if not all(k in values for k in required): return 'There are values missing', 400 # Adds a new transaction by utilizing our function index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount']) output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'} return jsonify(output), 201 @app.route('/nodes/add', methods=['POST']) def add_nodes(): values = request.get_json() nodes = values.get('nodes') if nodes is None: return "You didn't post a valid list of nodes. Please double check your input!", 400 for node in nodes: myblockchain.add_node(node) response = { 'message': 'All of your specified nodes have been added to the network!', 'total_nodes': list(myblockchain.nodes), } return jsonify(response), 201 @app.route('/nodes/resolve', methods=['GET']) def consensus(): replaced = myblockchain.resolve() if replaced: response = { 'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.', 'new_chain': myblockchain.blockchain } else: response = { 'message': 'The blockchain of this node is already the longest valid chain within the network.', 'chain': myblockchain.blockchain } return jsonify(response), 200 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` # Final thoughts And there you have it! Your very own blockchain. Wasn't very hard, was it? I sincerely hope you had fun thorughout this tutorial and were able to understand the concept and system behind it better. If you have any questions, please ask them in the comments and I'll try my best to answer them. # The obligatory begging As this whole tutorial took me over 2 days to finish, I would love to see a lot of comments and feedback under this post. Also if you find any typos, grammar mistakes, etc. and care to tell me, i would be mor than happy about it, as English is not my native language. So please excuse any mistakes I made. I tried my very best. Of course please upvote, if you worship my effort to enrich the community, and if you want to see more such content, consider following me. I wish you only the best - See ya!
json metadata{"tags":["steemit","blockchain","trevonjb","cryptocurrency","craigrant"],"links":["https://www.python.org/downloads/windows/","https://en.wikipedia.org/wiki/Integrated_development_environment","https://www.jetbrains.com/pycharm","https://www.getpostman.com/","https://curl.haxx.se/","https://en.wikipedia.org/wiki/SHA-2","https://en.wikipedia.org/wiki/Proof-of-work_system"],"app":"steemit/0.1","format":"markdown"}
parent author
parent permlinksteemit
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
titleCreate your own blockchain & cryptocurrency! - understand blockchains by creating one in python - no knowledge required
Transaction InfoBlock #18742287/Trx 1f80156352fe9f67a101ccd1e7eb3256f194e999
View Raw JSON Data
{
  "block": 18742287,
  "op": [
    "comment",
    {
      "author": "dustvoice",
      "body": "# What exactly is a blockchain?\n- How does a blockchain work?\n- What is Bitcoin or STEEM exactly?\n- How does a blockchain make sure of its correctness\n- What is **mining** exactly?\n\n**These are only some questions, probably many of you are asking yourselves. \nI'm here to provide you with kind of an unusual answer.\nMy goal is to help you undestand the whole system behind blockchains, by actually creating a small blockchain yourself!**\n\nWith the rise of cryptocurrencies and decentralized systems like Bitcoin or STEEM, many people want to really undestand, what this is all about. I will show you how the system works, by coding a blockchain from scratch in python with you. The guide will be mainly for Windows, but I will also add comments regarding Linux. You don't know a whole of python, to follow this guide, but it is advised to know the most basic basics.\n\n# Get ready\n## Setup Python and pip\nFirst off, we need to install Python 3.6+ along with pip, with which you can install python packages. \n- On **Linux**, you can install python, by simply typing `sudo apt-get install python3.6` into the terminal. If you encounter errors, please try `sudo apt-get update` and then try to execute the command again. If it still doesn't work, please search for installation instructions for your specific system on your preferred search engine.\n- On **Windows**,\n  1. first download the binary, that suits your system best, under the [official python download page for windows.](https://www.python.org/downloads/windows/). Make sure you grab at least the _version 3.6_ or higher.\n  2. Install the file you just downloaded. Make sure you check the option to install pip, when provided with an option to do so. If not, don't worry, it probably is enabled by default.\n\n## IDE or not?\nAs a next step, you want to decide, whether to utilize an [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) or not. An IDE is an environment, which supports you in the creation process of your application, by providing many features, with for example syntax highlighting, or code completion, to name just 2 possible features. My favorite IDE for Python development is probably PyCharm, which you can fetch from [this link.](https://www.jetbrains.com/pycharm) Setting up PyCharm on Windows is as simple, as downloading the executable installer and installing it with the provided setup utility. PyCharm is free tu use, as long as you use the Community Edition.\nYou can also use your coding notepad of choice. We will only work in one file, which you have to execute, so as long as your text-editing software is able to produce files with the ending `.py`, it will work fine.\n\n## Setup your workspace (PyCharm)\nIf you decided to use PyCharm, simply open it up and click on _Create Project_ in the popup dialogue. In the next dialogue you want to specify your project's name. I chose to use _MyBlockChain_ as my project name. Finally click on _create_ in the bottom right corner. On your left hand side, you're now provided with a file tree. \n1. Right-Click on the folder which consists of your project's name, in my case _MyBlockChain_\n2. Go to _new_ \n3. Finally click on _Python File_ and\n4. Define a Filename. I chose `MyBlockChain.py` as my filename.\n\n## Create your file (Simple Text Editor)\nIf you use a simple text editor, just create a file anywhere you like with the file extension `.py`. In my case I chose to use the filename `MyBlockChain.py`.\n\n## Install the needed packages\n### PyCharm\nIn PyCharm you can install packages very easily and add them to your project:\n1. Make sure, you have your project open\n2. Go to _File_ -> _Settings_ -> _Project: [your project name]_ -> _Project Interpreter_\n3. Then click on the green plus symbol.\n4. In the search field type in _Flask_ first. Select the first entry, which simply says _Flask_. Then click on Install Package in the bottom left corner.\n5. Do the same thing for _Requests_.\n### Pip\nIf you chose not to use PyCharm, you simply need to open up the terminal on linux or the command prompt, or PowerShell on Windows _(simply press **Windows+R** and type in cmd)_ and then execute `pip install Flask==0.12.2 requests==2.18.4 `. If this gives you an error, please double check that you have _pip_ installed. If the problem still occurs, please troubleshoot the error message using google, as there are too many possibilities, what the error could be caused by, for me to discuss every one of them here.\n\n## Getting a HTTP-Client\nYou will also need a HTTP-Client, as we need to make `GET` and `POST` requests to our Flask instance, at some Point in time. Mainly, there are two options - [_Postman_](https://www.getpostman.com/) or [_cURL_](https://curl.haxx.se/). I highly recommend _Postman_, as it is easy and intuitive to use, but if you just want a simple and quick solution, without having to register for an account, just use _cURL_. Online solutions, probably won't work, as the webserver you are going to be trying to access, is just on your local machine. \n\n## Just gimme the source code!\nIf you just want the source code and don't want to follow my instructions, please scroll down, to the very end of this post, where I will add the source code in its complete beauty.\n\n# The Blockchain - Your Blockchain\n## Step 1: Creating a simplistic Blockchain\nA block chain is basically a chain of blocks that are linked together in some way, as you have already figured. In this case, every block contains a hash of the previous block. A hash is a hexadecimal number that is determined by a specific algorithm. Imagine a hash being a digital fingerprint of an item. A good hash algorithm will never return the same hash for two different items, so every hash is individual. In our case we will be using the [_SHA-256_](https://en.wikipedia.org/wiki/SHA-2) algorithm. Furthermore the hash algorithm is not reversible, so you can't determine the object, by having its hash, but you can always apply the hash algorithm on the object, to get its hash. As every item has the hash of its previous item, the blockchain is protected against violation, as one would have to change every following block, as the hash changes with every change, as two different items can't have the same hash.\n### The Blockchain class\nOur Blockchain class basically consists of a constructor and some functions. In the constructor, we will create two empty lists - one to store our blockchain in and another, for our transactions. As for now, our class will have several functions:\n- A function to create new blocks\n- A function to create new transactions\n- A function, which hashes a block\n- A function to fetch the last block\nThe python template looks like this:\n```python\nclass MyBlockChain(object):\n    def __init__(self):\n        self.blockchain = []\n        self.transactions = []\n        \n    def create_new_block(self):\n        # This function creates a new block and appends it to the chain\n        pass\n    \n    def create_new_transaction(self):\n        # This function creates a new transaction and adds it to the list of transactions\n        pass\n    \n    @staticmethod\n    def hash(block):\n        # This method hashes the passed block\n        pass\n\n    @property\n    def last_block(self):\n        # This function returns the last block in the chain\n        pass\n```\n## Step 2: The blocks\nAs described earlier, a blockchain consists of blocks. So I will cover them first.\nEach Block has 5 fields:\n- An index,\n- an Unix timestamp,\n- a list of transactions,\n- a proof,\n- and finally the hash of the previous block.\nJust to clarify things, here is an example of a block\n```json\nexample_block = {\n    'index': 5,\n    'timestamp': 1515110045.123456,\n    'transactions': \n    [\n        {\n            'sender': \"154d8554f9541e12354e1234f512a001\",\n            'recipient': \"8654e21254c6512a51bce156542d1e5c\",\n            'amount': 212,\n        }\n    ],\n    'proof': 488612354568,\n    'previous_hash': \"c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e\"\n}\n```\n## Step 3: Hashing it\nAs every block needs the hash of the previous block, we need a function, that calculates the hash of a block. To accomplish this, we simply modify our empty `hash` function\n```python\nimport hashlib\nimport json\n\nclass MyBlockChain(object):\n    [...]\n    @staticmethod\n    def hash(block):\n        \"\"\"\n        This function hashes the block using the SHA-256 hash algorithm\n        The function is given a block and returns a string, consisting of the hash\n        :param block: <dict> Block\n        :return: <str>\n        \"\"\"\n\n        # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes\n        block_sorted = json.dumps(block, sort_keys=True).encode()\n        return hashlib.sha256(block_sorted).hexdigest()\n```\n## Step 4: Transactions\nOur `create_new_transaction` method is responsible for adding new transactions to the `transactions` list, which will then be stored inside a block. The whole function is pretty self explanatory. But first we need a function to return the last block of the chain, as we will calculate the new index, at which the transaction will be stored, by increasing the index of the last block by 1\n```python\nclass MyBlockChain(object):\n    [...]\n    @property\n    def last_block(self):\n        return self.blockchain[-1]\n```\nNow we can fill out the `create_new_transaction` function\n```python\nclass MyBlockChain(object):\n    [...]\n    def create_new_transaction(self, sender, recipient, amount):\n        \"\"\"\n        This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions.\n        \n        :param sender: <str> Sender's address\n        :param recipient: <str> Recipient's address\n        :param amount: <int> Amount to be transferred\n        :return: <int> This is the index of the block that will contain this transaction\n        \"\"\"\n\n        self.transactions.append({\n            'sender': sender,\n            'recipient': recipient,\n            'amount': amount,\n        })\n\n        return self.last_block['index'] + 1\n```\n## Step 5: Creating new Blocks\nBy now we almost have everything at our hands, what we need in order to make a new block. The only thing missing is the _proof_ field. As this is a little harder to understand, I will explain it later. \nBut we still have one problem - if every block has the hash of the previous block, what shall we do with our first block, as there is no previous block for us to hash. \nThis first block is called the _genesis_ block.\n```python\nimport hashlib\nimport json\nfrom time import time\n\nclass MyBlockChain(object):\n    def __init__(self):\n        self.blockchain = []\n        self.transactions = []\n\n        # Creation of the mentioned genesis block\n        self.create_new_block(previous_hash=1, proof=100)\n\n    def create_new_block(self, proof, previous_hash=None):\n        \"\"\"\n        Creates a new block and adds it to the blockchain\n        :param proof: <int> This is generated by the proof of work algorithm\n        :param previous_hash: (Optional) <str> Hash of the preleading Block\n        :return: <dict> Return the new block\n        \"\"\"\n\n        new_block = {\n            'index': len(self.blockchain) + 1,\n            'timestamp': time(),\n            'transactions': self.transactions,\n            'proof': proof,\n            'previous_hash': previous_hash or self.hash(self.blockchain[-1]),\n        }\n\n        # As all pending transactions have been processed and added to the block, the list can be resetted\n        self.transactions = []\n        \n        # Add the new block to the blockchain\n        self.blockchain.append(new_block)\n        return new_block\n```\n##  Step 6: What's up with the proof?!\n### The [Proof of Work (PoW) algorithm](https://en.wikipedia.org/wiki/Proof-of-work_system)\nThis system wants to **proof** that work has been done. Now a little bit less abstract. Basically we are searching for a number that matches a specific criteria. The thing is, for the system to work, the process of finding a number matching the criteria has to be **difficult**, but the verification process has to be **quick and easy**. This is how new blocks are created, or expressed in another, more commonly used term, _mined_.\n#### Still too abstract? Ok here is an example:\nWe are looking for a hash of a product of two integers that ends with a 1.\nSo the result of the multiplication of `a` and `b` gets hashed and has to end with a 1. If we set a to `a` static value, our algorithm will determine a value for `b`, for which this criteria is matched. \n```python\nfrom hashlib import sha256\na = 12\nb = 0  # We don't know what b has to be. It will be determined by the algorithm\nwhile sha256(f'{a*b}'.encode()).hexdigest()[-1] != \"1\":\n    b += 1\nprint(f'The solution is b = {b}')\n```\nThis example outputs\n```\nThe solution is b = 4\n```\nThis means that the hash of `12*4` ends with a 1\n```\nhash(48) = 98010bd9270f9b100b6214a21754fd33bdc8d41b2bc9f9dd16ff54d3c34ffd71\n```\nAs you can tell, the verification process doesn't need countless loops, until it finds a matching pair. You just have to run the hash algorithm once on the numbers and you can easily determine, whether the numbers match the criteria, or not.\n## Step 7: Implementing PoW\nFirstoff, we need a criteria, or commonly referred to as a rule. For now, our rule is that the hash has to have 5 leading zeroes, so `000005bc845e...` would be a valid result, but `000019ea76c4` would not. As the difficulty rises extremely, if we would require 6 leading zeros, the difficulty of our simple algorithm can be adjusted by changing the amount of leading zeroes required. This is the implementation in python:\n```python\n[...]\nfrom uuid import uuid4\n\nclass MyBlockChain(object):\n    [...]\n        \n    def pow(self, last_proof):\n        \"\"\"\n        Simple PoW Algorithm:\n         - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof.\n        :param last_proof: <int>\n        :return: <int>\n        \"\"\"\n        \n        current_proof = 0\n        while self.validate_proof(last_proof, current_proof) is False:\n            current_proof += 1\n\n        return current_proof\n\n    @staticmethod\n    def validate_proof(last_proof, current_proof):\n        \"\"\"\n        Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes.\n        :param last_proof: <int> Previous Proof Number\n        :param current_proof: <int> Current Proof Number\n        :return: <bool>\n        \"\"\"\n\n        possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest()\n        return possible_hash[:5] == \"00000\"\n```\n## Step 8: Interacting with our class\nNow we are able to create a blockchain. But we can't really interact with it, as we have only interacted with the functions and variables of our class.\nWe are going to use HTTP requests to interact with our blockchain. So let's set it up!\n# HTTP in the house!\nTo talk to our blockchain using Http requests, we need some help - which comes in the form of the _Flask Framework_. We will create and implement 3 basic methods for now:\n- `/blockchain` to retrieve the full blockchain\n- `/mining` to make our simple server mine a block\n- `/transactions/add` to add a new transaction to the blockchain.\n## Step 9: Flask\nFirst we need to implement Flask. Here is the code:\n```python\n[...]\nfrom textwrap import dedent\nfrom flask import Flask, jsonify, request\n\nclass MyBlockChain(object):\n    [...]\n    \napp = Flask(__name__)\nnode_identifier = str(uuid4()).replace('-', '')\n\nmyblockchain = MyBlockChain()\n\[email protected]('/blockchain', methods=['GET'])\ndef get_full_chain():\n    output = {\n        'chain': myblockchain.blockchain,\n        'length': len(myblockchain.blockchain),\n    }\n    return jsonify(output), 200\n\[email protected]('/mining', methods=['GET'])\ndef mining():\n    pass\[email protected]('/transactions/add', methods=['POST'])\ndef add_transaction():\n    pass\nif __name__ == '__main__':\n    app.run(host='0.0.0.0', port=5000)\n```\n## Step 10: Adding Transactions\nAs this is commonly the main task of a block chain and also required for a new block, I will cover this first. The user sends a _POST request_ to `/transactions/add` with a JSON object, containing all required fields. This is an example, for a possible, valid request:\n```json\n{\n \"sender\": \"154d8554f9541e12354e1234f512a001\",\n \"recipient\": \"8654e21254c6512a51bce156542d1e5c\",\n \"amount\": 212\n}\n```\nAs you can see, a request has three fields:\n- A _sender_ field, with the sender id,\n- a _recipient_ field, with the recipient id\n- and an amount, which defines how many units are to be transferred\nNow we just need to implement this function\n```python\n[...]\n\[email protected]('/transactions/add', methods=['POST'])\ndef add_transaction():\n    values = request.get_json()\n\n    # The POST request has to have the following required fields\n    required = ['sender', 'recipient', 'amount']\n    if not all(k in values for k in required):\n        return 'There are values missing', 400\n\n    # Adds a new transaction by utilizing our function\n    index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount'])\n\n    output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'}\n    return jsonify(output), 201\n```\nThis function simply calls the `create_new_transaction` method with the parameters of the POST request\n## Step 11: Setup your mines\nAs discussed earlier, future blocks have to be mined. If a new block is found/mined, all pending transactions are added to this block. To 'mine' a new block, our function hast to do three things\n1. Calculate the proof\n2. Reward the miner with a specific amount of coins (in our example 1 coin)\n3. Add the new mined block to the blockchain\n_(The fact that the recipient is our current node, will make more sense, as we will talk about decentralization later on.)_\n```python\[email protected]('/mining', methods=['GET'])\ndef mining():\n    # Calculate the new proof by using our PoW algorithm\n    last_block = myblockchain.last_block\n    last_proof = last_block['proof']\n    proof = myblockchain.pow(last_proof)\n\n    # For finding/mining the proof, the miner is granted a reward\n    # The sender is nobody, as this coin is coming out of the void\n    myblockchain.create_new_transaction(\n        sender=\"0\",\n        recipient=node_identifier,\n        amount=1,\n    )\n\n    # Add the new created block to the chain\n    previous_hash = myblockchain.hash(last_block)\n    newblock = myblockchain.create_new_block(proof, previous_hash)\n\n    output = {\n        'message': \"A new block was mined\",\n        'index': newblock['index'],\n        'transactions': newblock['transactions'],\n        'proof': newblock['proof'],\n        'previous_hash': newblock['previous_hash'],\n    }\n    return jsonify(output), 200\n```\n# Hello World!\nNow, **finally** we will be interacting with our blockchain API. Grab your HTTP client of choice and get going! I will explain the procedure for Postman and cURL.\n## Step 12: Start up the chain\nFirst off fire up your server. \nIn PyCharm simply click on _Run_ -> _Run..._ and select _[your filename].py_ as the file to run, in my case _myblockchain.py_.\nIf you chose to use a simple python file without an IDE, fire up a terminal or command prompt window inside the directory your file is located in and execute the following command\n```\npython blockchain.py\n```\nas a result you will see something similar to this\n```\n$ python blockchain.py\n* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n```\n**Note that you may be prompted with a dialogue of your firewall. Just accept it.**\n## Step 13: Mining it all!\nOk let's try the most exciting thing first, **mining**. I'm sure you can't wait to mine your first block, so let's do it!\nAs you can see in the code\n```python\n[...]\[email protected]('/mining', methods=['GET'])\ndef mining():\n    [...]\n```\nwe will be interacting with the `mining` part of our API through `GET` requests. This makes sense, as our only goal with this part of the API is, to mine a new block. We don't have to pass anything to the function at all, so a `GET` request is the way to go.\n### Postman\nIf you chose to use Postman, here is a quick tutorial on how to make a post request. \n1. First you have to register for an account, if you haven't already done that\n2. and login after that. \n3. If you are logged in, you shoudl be provided with several options such as _Request_, _Collection_, _Environment_.\n4. You could simply use the option _Request_, but to keep things organized, we are going to select the _Collection_ option. \n5. After that simply choose a name for your collection, in my case I'm using _MyBlockChain_ as my name.\n6. Now click on the _New_ Button, located in the top left corner and select _Request_ this time. We are now going to be creating 3 requests.\n7. The first request is going to be our _mining_ request, second is a _new transaction_ request and finally we will have a _get whole blockchain_ request. Of course you can customize the request names as you like. \n8. **Make sure, as you create these 3 requests, that you select our newly created Collection in the bottom section of the dialogue!**\n9. Now click on our Collection's folder in the left sidebar. You should see your 3 newly created requests. Select the _mining_ request first.\n10. On the right you are now provided with an interface. As you can see by the selected item from the dropdown box, left to the text field, a `GET` request is the standard request type, so we don't have to change that yet. \n11. In the text field `Enter request URL` we are now going to enter the `mining` URL of our API, so enter `http://localhost:5000/mining` as the request URL.\n### cURL\nIf you chose to use cURL as your HTTP client, simply type `curl -i -H \"Content-Type: application/json\" -X GET http://localhost:5000/mining` in a terminal window\n### Either way\nWith both methods you should see something similar to this as a result\n```json\n{\n    \"index\": 2,\n    \"message\": \"New Block Forged\",\n    \"previous_hash\": \"0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a\",\n    \"proof\": 888273,\n    \"transactions\": [\n        {\n            \"amount\": 1,\n            \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n            \"sender\": \"0\"\n        }\n    ]\n}\n```\n## Step 14: Transactions are great!\nAs our mining algorithm seems to be working fine, let's create a new transaction, to be stored in a fresh mined block. To do that in\n### Postman\n1. Click on the _new transaction_ request in the left sidebar.\n2. Click on the _GET_ button with the small arrow pointing down.\n3. Select _POST_ from the drop-down list.\n4. In the navbar below the text field, select _Body_ \n5. and then mark the _raw_ option.\n6. You should now be provided with an editor like text area, and another drop-down menu next to the _binary_ option, where _Text_ is currently selected. Select _JSON (application/json)_ from this list.\n7. Now type in the following into the text area.\n```json\n{\n \"sender\": \"your-node-address\",\n \"recipient\": \"another-node-address\",\n \"amount\": 212\n}\n```\n### cURL\nJust execute `curl -X POST -H \"Content-Type: application/json\" -d '{\"sender\": \"your-node-address\", \"recipient\": \"another-node-address\", \"amount\": 212}' \"http://localhost:5000/transactions/add\"` in a terminal window.\n### In both cases\nReplace `your-node-address` with the _recipient_ address from you mining request, as this is your node address. You can also select any other 32 digit hexadezimal number, for now. Furthermore replace `another-node-address` with a random 32 digit hexadezimal number for now, as we currently don't have any other nodes.\nAdjust the `amount` to your liking.\nAnd **voilà**! You have registered your first transaction!\n## Step 15: The Chain...\nSo let's inspect our chain! If you're using\n### Postman\nClick on the _get whole blockchain_ request in the left sidebar and simply enter `http://localhost:5000/blockchain` in the `Enter request URL` text field, as _GET_ should be preselected. If not, please change it to the _GET_ option.\n### cURL\njust execute  `curl -i -H \"Content-Type: application/json\" -X GET http://localhost:5000/blockchain` in a terminal window.\n### Either way\nyou should get your whole blockchain in form of a JSON-Object. In my case, my blockchain looks like this, after mining 2 times, adding 3 transactions and mining another block:\n```json\n{\n    \"chain\": [\n        {\n            \"index\": 1,\n            \"previous_hash\": \"1\",\n            \"proof\": 100,\n            \"timestamp\": 1515156902.4502413,\n            \"transactions\": []\n        },\n        {\n            \"index\": 2,\n            \"previous_hash\": \"0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a\",\n            \"proof\": 888273,\n            \"timestamp\": 1515156913.2686973,\n            \"transactions\": [\n                {\n                    \"amount\": 1,\n                    \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n                    \"sender\": \"0\"\n                }\n            ]\n        },\n        {\n            \"index\": 3,\n            \"previous_hash\": \"1d2ae4a41f4a82ce6f04944e8227bf9c4d951d560f8763b910d7314634dfe09c\",\n            \"proof\": 1156297,\n            \"timestamp\": 1515158367.3596537,\n            \"transactions\": [\n                {\n                    \"amount\": 212,\n                    \"recipient\": \"d4ee26eee15148ee92c6cd394edd974e\",\n                    \"sender\": \"491002ea048a42609d967027cc46a07b\"\n                },\n                {\n                    \"amount\": 212,\n                    \"recipient\": \"5654c5654e1b551a65e15f5e4651c156\",\n                    \"sender\": \"491002ea048a42609d967027cc46a07b\"\n                },\n                {\n                    \"amount\": 111,\n                    \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n                    \"sender\": \"5654c5654e1b551a65e15f5e4651c156\"\n                },\n                {\n                    \"amount\": 1,\n                    \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n                    \"sender\": \"0\"\n                }\n            ]\n        }\n    ],\n    \"length\": 3\n}\n```\n# Decentralizing it\nOk, so we got a blockchain, that's working fine and we can interact with it. But one very important thing is still missing: **Decentralization**. \nThis is a core element of the blockchain idea. \nFirst off by decentralizing the whole thing, safety and integrity of the blockchain is guaranteed, as a change in the blockchain will be recognized, by the other nodes, as they also have a copy of the blockchain, and discarded. \nThe second reason is that we somehow have to make sense of our transactions. For this we need other nodes and why shouldn't they contribute to our network, by being a part of the blockchain system?! \nBut we still have a conflict there: What if a node has a blockchain that differs from all the others? \nFor our simple blockchain we will always make the **longest valid** blockchain authorative.\n## Step 16: Someone out there?!\nBut first things first. \nTo get started, we first have to implement other nodes into our system.\nTo accomplish this task, we have to adjust a few things in our API. First off, we are going to implement some new endpoints:\n1. `/nodes/add` to add new nodes in form of a list of URLs\n2. `/nodes/resolve` to resolve the conflict we discussed previously by using a consensus algorithm.\nTo do this, we have to modify our Blockchain class first:\n```python\n[...]\nfrom urllib.parse import urlparse\n\nclass MyBlockChain(object):\n    def __init__(self):\n        [...]\n        self.nodes = set()\n\n    def add_node(self, address):\n        \"\"\"\n        Register a new node\n        :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000'\n        :return: None\n        \"\"\"\n\n        node_url = urlparse(address)\n        self.nodes.add(node_url.netloc)\n```\n## Step 17: We need Consensus\nTo resolve the conflict of differing blockchains between the nodes, we are going to implement a consensus algorithm. As we discussed earlier, we are always utilizing the longest valid blockchain.\nFirst we are implementing a function that validates a blockchain:\n```python\n[...]\nimport requests\n\nclass MyBlockChain(object)\n    [...]\n    \n    def validate_blockchain(self, test_chain):\n        \"\"\"\n        Evaluate, whether a blockchain is valid\n        :param chain: <list> The blockchain that shall be tested\n        :return: <bool> Returns true if the blockchain is valid\n        \"\"\"\n\n        last_block = test_chain[0]\n        current_index = 1\n\n        while current_index < len(test_chain):\n            block = test_chain[current_index]\n            \n            # Determine, whether the hash is correct\n            if block['previous_hash'] != self.hash(last_block):\n                return False\n\n            # Determine, wheter the proof of work is correct\n            if not self.validate_proof(last_block['proof'], block['proof']):\n                return False\n\n            last_block = block\n            current_index += 1\n\n        return True\n```\nNow we just have to run every blockchain in our surrounding network through this consensus algorithm:\n```python\n [...]\n\nclass MyBlockChain(object)\n    [...]\n    def resolve(self):\n        \"\"\"\n        This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously.\n        :return: <bool> Returns true, if our chain was substituted with an updated version\n        \"\"\"\n\n        surrounding_nodes = self.nodes\n        updated_chain = None\n\n        # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain\n        max_length = len(self.blockchain)\n\n        # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain.\n        for node_iterator in surrounding_nodes:\n            response = requests.get(f'http://{node_iterator}/blockchain')\n\n            if response.status_code == 200:\n                length = response.json()['length']\n                chain_iterator = response.json()['chain']\n\n                if length > max_length and self.validate_blockchain(chain_iterator):\n                    max_length = length\n                    updated_chain = chain_iterator\n\n        # If we found a new blockchain, replace our current blockchain with the new one\n        if updated_chain:\n            self.blockchain = updated_chain\n            return True\n\n        return False\n```\nNow we just have to register our new functions as new endpoints in the API:\n```python\[email protected]('/nodes/add', methods=['POST'])\ndef add_nodes():\n    values = request.get_json()\n\n    nodes = values.get('nodes')\n    if nodes is None:\n        return \"You didn't post a valid list of nodes. Please double check your input!\", 400\n\n    for node in nodes:\n        myblockchain.add_node(node)\n\n    response = {\n        'message': 'All of your specified nodes have been added to the network!',\n        'total_nodes': list(myblockchain.nodes),\n    }\n    return jsonify(response), 201\n\n\[email protected]('/nodes/resolve', methods=['GET'])\ndef consensus():\n    replaced = myblockchain.resolve()\n\n    if replaced:\n        response = {\n            'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.',\n            'new_chain': myblockchain.blockchain\n        }\n    else:\n        response = {\n            'message': 'The blockchain of this node is already the longest valid chain within the network.',\n            'chain': myblockchain.blockchain\n        }\n\n    return jsonify(response), 200\n```\n## Step 18: Friends are great. Even if they're virtual...\nTo test our decentralization algorithms, either grab some friends, to run some nodes for you, or just run the same program on different ports, so you would have to start up an instance of our blockchain-program, then change to port to 5001 for example, save, fire up an instance of this _modified_ program, change the port to 5002, etc. \n## Step 19: Add them to your friends list\nIf you got some instances, you just have to register them. To do this, simply send a `POST` request with the following content\n```json\n{\n    \"nodes\": [\"http://[ip-of-another-node-or-127.0.0.1-for-your-local-machine]:[the-port-number]\"]\n}\n```\nto `http://[the-node-ip-you-want-to-register-it-to]:[port]/nodes/add`\n## Step 20: Consensus check\nAfter that try to mine some blocks and even add some transactions on let's say node 2 and then run `http://[a-node-ip]:[port]/nodes/resolve` on let's say node 1. The consensus algorithm should step into action and update the blockchain of node 1.\n# The whole thang\nI keep my promises\n```python\nimport hashlib\nimport json\nimport requests\nfrom time import time\nfrom uuid import uuid4\nfrom textwrap import dedent\nfrom flask import Flask, jsonify, request\nfrom urllib.parse import urlparse\n\nclass MyBlockChain(object):\n    def __init__(self):\n        self.blockchain = []\n        self.transactions = []\n        \n        # Creation of the mentioned genesis block\n        self.create_new_block(previous_hash=1, proof=100)\n        \n        self.nodes = set()\n        \n    def create_new_block(self, proof, previous_hash=None):\n        \"\"\"\n        Creates a new block and adds it to the blockchain\n        :param proof: <int> This is generated by the proof of work algorithm\n        :param previous_hash: (Optional) <str> Hash of the preleading Block\n        :return: <dict> Return the new block\n        \"\"\"\n\n        new_block = {\n            'index': len(self.blockchain) + 1,\n            'timestamp': time(),\n            'transactions': self.transactions,\n            'proof': proof,\n            'previous_hash': previous_hash or self.hash(self.blockchain[-1]),\n        }\n\n        # As all pending transactions have been processed and added to the block, the list can be resetted\n        self.transactions = []\n        \n        # Add the new block to the blockchain\n        self.blockchain.append(new_block)\n        return new_block\n    \n    def create_new_transaction(self, sender, recipient, amount):\n        \"\"\"\n        This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions.\n        \n        :param sender: <str> Sender's address\n        :param recipient: <str> Recipient's address\n        :param amount: <int> Amount to be transferred\n        :return: <int> This is the index of the block that will contain this transaction\n        \"\"\"\n\n        self.transactions.append({\n            'sender': sender,\n            'recipient': recipient,\n            'amount': amount,\n        })\n\n        return self.last_block['index'] + 1\n    \n    @staticmethod\n    def hash(block):\n        \"\"\"\n        This function hashes the block using the SHA-256 hash algorithm\n        The function is given a block and returns a string, consisting of the hash\n        :param block: <dict> Block\n        :return: <str>\n        \"\"\"\n\n        # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes\n        block_sorted = json.dumps(block, sort_keys=True).encode()\n        return hashlib.sha256(block_sorted).hexdigest()\n\n    @property\n    def last_block(self):\n        return self.blockchain[-1]\n        \n    def pow(self, last_proof):\n        \"\"\"\n        Simple PoW Algorithm:\n         - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof.\n        :param last_proof: <int>\n        :return: <int>\n        \"\"\"\n        \n        current_proof = 0\n        while self.validate_proof(last_proof, current_proof) is False:\n            current_proof += 1\n\n        return current_proof\n\n    @staticmethod\n    def validate_proof(last_proof, current_proof):\n        \"\"\"\n        Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes.\n        :param last_proof: <int> Previous Proof Number\n        :param current_proof: <int> Current Proof Number\n        :return: <bool>\n        \"\"\"\n\n        possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest()\n        return possible_hash[:5] == \"00000\"\n        \n    def add_node(self, address):\n        \"\"\"\n        Register a new node\n        :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000'\n        :return: None\n        \"\"\"\n\n        node_url = urlparse(address)\n        self.nodes.add(node_url.netloc)\n        \n    def validate_blockchain(self, test_chain):\n        \"\"\"\n        Evaluate, whether a blockchain is valid\n        :param chain: <list> The blockchain that shall be tested\n        :return: <bool> Returns true if the blockchain is valid\n        \"\"\"\n\n        last_block = test_chain[0]\n        current_index = 1\n\n        while current_index < len(test_chain):\n            block = test_chain[current_index]\n            \n            # Determine, whether the hash is correct\n            if block['previous_hash'] != self.hash(last_block):\n                return False\n\n            # Determine, wheter the proof of work is correct\n            if not self.validate_proof(last_block['proof'], block['proof']):\n                return False\n\n            last_block = block\n            current_index += 1\n\n        return True\n        \n    def resolve(self):\n        \"\"\"\n        This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously.\n        :return: <bool> Returns true, if our chain was substituted with an updated version\n        \"\"\"\n\n        surrounding_nodes = self.nodes\n        updated_chain = None\n\n        # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain\n        max_length = len(self.blockchain)\n\n        # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain.\n        for node_iterator in surrounding_nodes:\n            response = requests.get(f'http://{node_iterator}/blockchain')\n\n            if response.status_code == 200:\n                length = response.json()['length']\n                chain_iterator = response.json()['chain']\n\n                if length > max_length and self.validate_blockchain(chain_iterator):\n                    max_length = length\n                    updated_chain = chain_iterator\n\n        # If we found a new blockchain, replace our current blockchain with the new one\n        if updated_chain:\n            self.blockchain = updated_chain\n            return True\n\n        return False\n\napp = Flask(__name__)\nnode_identifier = str(uuid4()).replace('-', '')\n\nmyblockchain = MyBlockChain()\n\[email protected]('/blockchain', methods=['GET'])\ndef get_full_chain():\n    output = {\n        'chain': myblockchain.blockchain,\n        'length': len(myblockchain.blockchain),\n    }\n    return jsonify(output), 200\n\[email protected]('/mining', methods=['GET'])\ndef mining():\n    # Calculate the new proof by using our PoW algorithm\n    last_block = myblockchain.last_block\n    last_proof = last_block['proof']\n    proof = myblockchain.pow(last_proof)\n\n    # For finding/mining the proof, the miner is granted a reward\n    # The sender is nobody, as this coin is coming out of the void\n    myblockchain.create_new_transaction(\n        sender=\"0\",\n        recipient=node_identifier,\n        amount=1,\n    )\n\n    # Add the new created block to the chain\n    previous_hash = myblockchain.hash(last_block)\n    newblock = myblockchain.create_new_block(proof, previous_hash)\n\n    output = {\n        'message': \"A new block was mined\",\n        'index': newblock['index'],\n        'transactions': newblock['transactions'],\n        'proof': newblock['proof'],\n        'previous_hash': newblock['previous_hash'],\n    }\n    return jsonify(output), 200\n    \[email protected]('/transactions/add', methods=['POST'])\ndef add_transaction():\n    values = request.get_json()\n\n    # The POST request has to have the following required fields\n    required = ['sender', 'recipient', 'amount']\n    if not all(k in values for k in required):\n        return 'There are values missing', 400\n\n    # Adds a new transaction by utilizing our function\n    index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount'])\n\n    output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'}\n    return jsonify(output), 201\n    \[email protected]('/nodes/add', methods=['POST'])\ndef add_nodes():\n    values = request.get_json()\n\n    nodes = values.get('nodes')\n    if nodes is None:\n        return \"You didn't post a valid list of nodes. Please double check your input!\", 400\n\n    for node in nodes:\n        myblockchain.add_node(node)\n\n    response = {\n        'message': 'All of your specified nodes have been added to the network!',\n        'total_nodes': list(myblockchain.nodes),\n    }\n    return jsonify(response), 201\n\n\[email protected]('/nodes/resolve', methods=['GET'])\ndef consensus():\n    replaced = myblockchain.resolve()\n\n    if replaced:\n        response = {\n            'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.',\n            'new_chain': myblockchain.blockchain\n        }\n    else:\n        response = {\n            'message': 'The blockchain of this node is already the longest valid chain within the network.',\n            'chain': myblockchain.blockchain\n        }\n\n    return jsonify(response), 200\n\nif __name__ == '__main__':\n    app.run(host='0.0.0.0', port=5000)\n```\n# Final thoughts\nAnd there you have it!\nYour very own blockchain. Wasn't very hard, was it?\nI sincerely hope you had fun thorughout this tutorial and were able to understand the concept and system behind it better. If you have any questions, please ask them in the comments and I'll try my best to answer them.\n# The obligatory begging\nAs this whole tutorial took me over 2 days to finish, I would love to see a lot of comments and feedback under this post. Also if you find any typos, grammar mistakes, etc. and care to tell me, i would be mor than happy about it, as English is not my native language. So please excuse any mistakes I made. I tried my very best.\nOf course please upvote, if you worship my effort to enrich the community, and if you want to see more such content, consider following me. \nI wish you only the best - See ya!",
      "json_metadata": "{\"tags\":[\"steemit\",\"blockchain\",\"trevonjb\",\"cryptocurrency\",\"craigrant\"],\"links\":[\"https://www.python.org/downloads/windows/\",\"https://en.wikipedia.org/wiki/Integrated_development_environment\",\"https://www.jetbrains.com/pycharm\",\"https://www.getpostman.com/\",\"https://curl.haxx.se/\",\"https://en.wikipedia.org/wiki/SHA-2\",\"https://en.wikipedia.org/wiki/Proof-of-work_system\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
      "parent_author": "",
      "parent_permlink": "steemit",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "title": "Create your own blockchain & cryptocurrency! - understand blockchains by creating one in python - no knowledge required"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T14:08:54",
  "trx_id": "1f80156352fe9f67a101ccd1e7eb3256f194e999",
  "trx_in_block": 22,
  "virtual_op": 0
}
2018/01/06 14:07:54
authordustvoice
body# What exactly is a blockchain? - How does a blockchain work? - What is Bitcoin or STEEM exactly? - How does a blockchain make sure of its correctness - What is **mining** exactly? **These are only some questions, probably many of you are asking yourselves. I'm here to provide you with kind of an unusual answer. My goal is to help you undestand the whole system behind blockchains, by actually creating a small blockchain yourself!** With the rise of cryptocurrencies and decentralized systems like Bitcoin or STEEM, many people want to really undestand, what this is all about. I will show you how the system works, by coding a blockchain from scratch in python with you. The guide will be mainly for Windows, but I will also add comments regarding Linux. You don't know a whole of python, to follow this guide, but it is advised to know the most basic basics. # Get ready ## Setup Python and pip First off, we need to install Python 3.6+ along with pip, with which you can install python packages. - On **Linux**, you can install python, by simply typing `sudo apt-get install python3.6` into the terminal. If you encounter errors, please try `sudo apt-get update` and then try to execute the command again. If it still doesn't work, please search for installation instructions for your specific system on your preferred search engine. - On **Windows**, 1. first download the binary, that suits your system best, under the [official python download page for windows.](https://www.python.org/downloads/windows/). Make sure you grab at least the _version 3.6_ or higher. 2. Install the file you just downloaded. Make sure you check the option to install pip, when provided with an option to do so. If not, don't worry, it probably is enabled by default. ## IDE or not? As a next step, you want to decide, whether to utilize an [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) or not. An IDE is an environment, which supports you in the creation process of your application, by providing many features, with for example syntax highlighting, or code completion, to name just 2 possible features. My favorite IDE for Python development is probably PyCharm, which you can fetch from [this link.](https://www.jetbrains.com/pycharm) Setting up PyCharm on Windows is as simple, as downloading the executable installer and installing it with the provided setup utility. PyCharm is free tu use, as long as you use the Community Edition. You can also use your coding notepad of choice. We will only work in one file, which you have to execute, so as long as your text-editing software is able to produce files with the ending `.py`, it will work fine. ## Setup your workspace (PyCharm) If you decided to use PyCharm, simply open it up and click on _Create Project_ in the popup dialogue. In the next dialogue you want to specify your project's name. I chose to use _MyBlockChain_ as my project name. Finally click on _create_ in the bottom right corner. On your left hand side, you're now provided with a file tree. 1. Right-Click on the folder which consists of your project's name, in my case _MyBlockChain_ 2. Go to _new_ 3. Finally click on _Python File_ and 4. Define a Filename. I chose `MyBlockChain.py` as my filename. ## Create your file (Simple Text Editor) If you use a simple text editor, just create a file anywhere you like with the file extension `.py`. In my case I chose to use the filename `MyBlockChain.py`. ## Install the needed packages ### PyCharm In PyCharm you can install packages very easily and add them to your project: 1. Make sure, you have your project open 2. Go to _File_ -> _Settings_ -> _Project: [your project name]_ -> _Project Interpreter_ 3. Then click on the green plus symbol. 4. In the search field type in _Flask_ first. Select the first entry, which simply says _Flask_. Then click on Install Package in the bottom left corner. 5. Do the same thing for _Requests_. ### Pip If you chose not to use PyCharm, you simply need to open up the terminal on linux or the command prompt, or PowerShell on Windows _(simply press **Windows+R** and type in cmd)_ and then execute `pip install Flask==0.12.2 requests==2.18.4 `. If this gives you an error, please double check that you have _pip_ installed. If the problem still occurs, please troubleshoot the error message using google, as there are too many possibilities, what the error could be caused by, for me to discuss every one of them here. ## Getting a HTTP-Client You will also need a HTTP-Client, as we need to make `GET` and `POST` requests to our Flask instance, at some Point in time. Mainly, there are two options - [_Postman_](https://www.getpostman.com/) or [_cURL_](https://curl.haxx.se/). I highly recommend _Postman_, as it is easy and intuitive to use, but if you just want a simple and quick solution, without having to register for an account, just use _cURL_. Online solutions, probably won't work, as the webserver you are going to be trying to access, is just on your local machine. ## Just gimme the source code! If you just want the source code and don't want to follow my instructions, please scroll down, to the very end of this post, where I will add the source code in its complete beauty. # The Blockchain - Your Blockchain ## Step 1: Creating a simplistic Blockchain A block chain is basically a chain of blocks that are linked together in some way, as you have already figured. In this case, every block contains a hash of the previous block. A hash is a hexadecimal number that is determined by a specific algorithm. Imagine a hash being a digital fingerprint of an item. A good hash algorithm will never return the same hash for two different items, so every hash is individual. In our case we will be using the [_SHA-256_](https://en.wikipedia.org/wiki/SHA-2) algorithm. Furthermore the hash algorithm is not reversible, so you can't determine the object, by having its hash, but you can always apply the hash algorithm on the object, to get its hash. As every item has the hash of its previous item, the blockchain is protected against violation, as one would have to change every following block, as the hash changes with every change, as two different items can't have the same hash. ### The Blockchain class Our Blockchain class basically consists of a constructor and some functions. In the constructor, we will create two empty lists - one to store our blockchain in and another, for our transactions. As for now, our class will have several functions: - A function to create new blocks - A function to create new transactions - A function, which hashes a block - A function to fetch the last block The python template looks like this: ```python class MyBlockChain(object): def __init__(self): self.blockchain = [] self.transactions = [] def create_new_block(self): # This function creates a new block and appends it to the chain pass def create_new_transaction(self): # This function creates a new transaction and adds it to the list of transactions pass @staticmethod def hash(block): # This method hashes the passed block pass @property def last_block(self): # This function returns the last block in the chain pass ``` ## Step 2: The blocks As described earlier, a blockchain consists of blocks. So I will cover them first. Each Block has 5 fields: - An index, - an Unix timestamp, - a list of transactions, - a proof, - and finally the hash of the previous block. Just to clarify things, here is an example of a block ```json example_block = { 'index': 5, 'timestamp': 1515110045.123456, 'transactions': [ { 'sender': "154d8554f9541e12354e1234f512a001", 'recipient': "8654e21254c6512a51bce156542d1e5c", 'amount': 212, } ], 'proof': 488612354568, 'previous_hash': "c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e" } ``` ## Step 3: Hashing it As every block needs the hash of the previous block, we need a function, that calculates the hash of a block. To accomplish this, we simply modify our empty `hash` function ```python import hashlib import json class MyBlockChain(object): [...] @staticmethod def hash(block): """ This function hashes the block using the SHA-256 hash algorithm The function is given a block and returns a string, consisting of the hash :param block: <dict> Block :return: <str> """ # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes block_sorted = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_sorted).hexdigest() ``` ## Step 4: Transactions Our `create_new_transaction` method is responsible for adding new transactions to the `transactions` list, which will then be stored inside a block. The whole function is pretty self explanatory. But first we need a function to return the last block of the chain, as we will calculate the new index, at which the transaction will be stored, by increasing the index of the last block by 1 ```python class MyBlockChain(object): [...] @property def last_block(self): return self.blockchain[-1] ``` Now we can fill out the `create_new_transaction` function ```python class MyBlockChain(object): [...] def create_new_transaction(self, sender, recipient, amount): """ This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions. :param sender: <str> Sender's address :param recipient: <str> Recipient's address :param amount: <int> Amount to be transferred :return: <int> This is the index of the block that will contain this transaction """ self.transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1 ``` ## Step 5: Creating new Blocks By now we almost have everything at our hands, what we need in order to make a new block. The only thing missing is the _proof_ field. As this is a little harder to understand, I will explain it later. But we still have one problem - if every block has the hash of the previous block, what shall we do with our first block, as there is no previous block for us to hash. This first block is called the _genesis_ block. ```python import hashlib import json from time import time class MyBlockChain(object): def __init__(self): self.blockchain = [] self.transactions = [] # Creation of the mentioned genesis block self.create_new_block(previous_hash=1, proof=100) def create_new_block(self, proof, previous_hash=None): """ Creates a new block and adds it to the blockchain :param proof: <int> This is generated by the proof of work algorithm :param previous_hash: (Optional) <str> Hash of the preleading Block :return: <dict> Return the new block """ new_block = { 'index': len(self.blockchain) + 1, 'timestamp': time(), 'transactions': self.transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.blockchain[-1]), } # As all pending transactions have been processed and added to the block, the list can be resetted self.transactions = [] # Add the new block to the blockchain self.blockchain.append(new_block) return new_block ``` ## Step 6: What's up with the proof?! ### The [Proof of Work (PoW) algorithm](https://en.wikipedia.org/wiki/Proof-of-work_system) This system wants to **proof** that work has been done. Now a little bit less abstract. Basically we are searching for a number that matches a specific criteria. The thing is, for the system to work, the process of finding a number matching the criteria has to be **difficult**, but the verification process has to be **quick and easy**. This is how new blocks are created, or expressed in another, more commonly used term, _mined_. #### Still too abstract? Ok here is an example: We are looking for a hash of a product of two integers that ends with a 1. So the result of the multiplication of `a` and `b` gets hashed and has to end with a 1. If we set a to `a` static value, our algorithm will determine a value for `b`, for which this criteria is matched. ```python from hashlib import sha256 a = 12 b = 0 # We don't know what b has to be. It will be determined by the algorithm while sha256(f'{a*b}'.encode()).hexdigest()[-1] != "1": b += 1 print(f'The solution is b = {b}') ``` This example outputs ``` The solution is b = 4 ``` This means that the hash of `12*4` ends with a 1 ``` hash(48) = 98010bd9270f9b100b6214a21754fd33bdc8d41b2bc9f9dd16ff54d3c34ffd71 ``` As you can tell, the verification process doesn't need countless loops, until it finds a matching pair. You just have to run the hash algorithm once on the numbers and you can easily determine, whether the numbers match the criteria, or not. ## Step 7: Implementing PoW Firstoff, we need a criteria, or commonly referred to as a rule. For now, our rule is that the hash has to have 5 leading zeroes, so `000005bc845e...` would be a valid result, but `000019ea76c4` would not. As the difficulty rises extremely, if we would require 6 leading zeros, the difficulty of our simple algorithm can be adjusted by changing the amount of leading zeroes required. This is the implementation in python: ```python [...] from uuid import uuid4 class MyBlockChain(object): [...] def pow(self, last_proof): """ Simple PoW Algorithm: - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof. :param last_proof: <int> :return: <int> """ current_proof = 0 while self.validate_proof(last_proof, current_proof) is False: current_proof += 1 return current_proof @staticmethod def validate_proof(last_proof, current_proof): """ Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes. :param last_proof: <int> Previous Proof Number :param current_proof: <int> Current Proof Number :return: <bool> """ possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest() return possible_hash[:5] == "00000" ``` ## Step 8: Interacting with our class Now we are able to create a blockchain. But we can't really interact with it, as we have only interacted with the functions and variables of our class. We are going to use HTTP requests to interact with our blockchain. So let's set it up! # HTTP in the house! To talk to our blockchain using Http requests, we need some help - which comes in the form of the _Flask Framework_. We will create and implement 3 basic methods for now: - `/blockchain` to retrieve the full blockchain - `/mining` to make our simple server mine a block - `/transactions/add` to add a new transaction to the blockchain. ## Step 9: Flask First we need to implement Flask. Here is the code: ```python [...] from textwrap import dedent from flask import Flask, jsonify, request class MyBlockChain(object): [...] app = Flask(__name__) node_identifier = str(uuid4()).replace('-', '') myblockchain = MyBlockChain() @app.route('/blockchain', methods=['GET']) def get_full_chain(): output = { 'chain': myblockchain.blockchain, 'length': len(myblockchain.blockchain), } return jsonify(output), 200 @app.route('/mining', methods=['GET']) def mining(): pass @app.route('/transactions/add', methods=['POST']) def add_transaction(): pass if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` ## Step 10: Adding Transactions As this is commonly the main task of a block chain and also required for a new block, I will cover this first. The user sends a _POST request_ to `/transactions/add` with a JSON object, containing all required fields. This is an example, for a possible, valid request: ```json { "sender": "154d8554f9541e12354e1234f512a001", "recipient": "8654e21254c6512a51bce156542d1e5c", "amount": 212 } ``` As you can see, a request has three fields: - A _sender_ field, with the sender id, - a _recipient_ field, with the recipient id - and an amount, which defines how many units are to be transferred Now we just need to implement this function ```python [...] @app.route('/transactions/add', methods=['POST']) def add_transaction(): values = request.get_json() # The POST request has to have the following required fields required = ['sender', 'recipient', 'amount'] if not all(k in values for k in required): return 'There are values missing', 400 # Adds a new transaction by utilizing our function index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount']) output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'} return jsonify(output), 201 ``` This function simply calls the `create_new_transaction` method with the parameters of the POST request ## Step 11: Setup your mines As discussed earlier, future blocks have to be mined. If a new block is found/mined, all pending transactions are added to this block. To 'mine' a new block, our function hast to do three things 1. Calculate the proof 2. Reward the miner with a specific amount of coins (in our example 1 coin) 3. Add the new mined block to the blockchain _(The fact that the recipient is our current node, will make more sense, as we will talk about decentralization later on.)_ ```python @app.route('/mining', methods=['GET']) def mining(): # Calculate the new proof by using our PoW algorithm last_block = myblockchain.last_block last_proof = last_block['proof'] proof = myblockchain.pow(last_proof) # For finding/mining the proof, the miner is granted a reward # The sender is nobody, as this coin is coming out of the void myblockchain.create_new_transaction( sender="0", recipient=node_identifier, amount=1, ) # Add the new created block to the chain previous_hash = myblockchain.hash(last_block) newblock = myblockchain.create_new_block(proof, previous_hash) output = { 'message': "A new block was mined", 'index': newblock['index'], 'transactions': newblock['transactions'], 'proof': newblock['proof'], 'previous_hash': newblock['previous_hash'], } return jsonify(output), 200 ``` # Hello World! Now, **finally** we will be interacting with our blockchain API. Grab your HTTP client of choice and get going! I will explain the procedure for Postman and cURL. ## Step 12: Start up the chain First off fire up your server. In PyCharm simply click on _Run_ -> _Run..._ and select _[your filename].py_ as the file to run, in my case _myblockchain.py_. If you chose to use a simple python file without an IDE, fire up a terminal or command prompt window inside the directory your file is located in and execute the following command ``` python blockchain.py ``` as a result you will see something similar to this ``` $ python blockchain.py * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) ``` **Note that you may be prompted with a dialogue of your firewall. Just accept it.** ## Step 13: Mining it all! Ok let's try the most exciting thing first, **mining**. I'm sure you can't wait to mine your first block, so let's do it! As you can see in the code ```python [...] @app.route('/mining', methods=['GET']) def mining(): [...] ``` we will be interacting with the `mining` part of our API through `GET` requests. This makes sense, as our only goal with this part of the API is, to mine a new block. We don't have to pass anything to the function at all, so a `GET` request is the way to go. ### Postman If you chose to use Postman, here is a quick tutorial on how to make a post request. 1. First you have to register for an account, if you haven't already done that 2. and login after that. 3. If you are logged in, you shoudl be provided with several options such as _Request_, _Collection_, _Environment_. 4. You could simply use the option _Request_, but to keep things organized, we are going to select the _Collection_ option. 5. After that simply choose a name for your collection, in my case I'm using _MyBlockChain_ as my name. 6. Now click on the _New_ Button, located in the top left corner and select _Request_ this time. We are now going to be creating 3 requests. 7. The first request is going to be our _mining_ request, second is a _new transaction_ request and finally we will have a _get whole blockchain_ request. Of course you can customize the request names as you like. 8. **Make sure, as you create these 3 requests, that you select our newly created Collection in the bottom section of the dialogue!** 9. Now click on our Collection's folder in the left sidebar. You should see your 3 newly created requests. Select the _mining_ request first. 10. On the right you are now provided with an interface. As you can see by the selected item from the dropdown box, left to the text field, a `GET` request is the standard request type, so we don't have to change that yet. 11. In the text field `Enter request URL` we are now going to enter the `mining` URL of our API, so enter `http://localhost:5000/mining` as the request URL. ### cURL If you chose to use cURL as your HTTP client, simply type `curl -i -H "Content-Type: application/json" -X GET http://localhost:5000/mining` in a terminal window ### Either way With both methods you should see something similar to this as a result ```json { "index": 2, "message": "New Block Forged", "previous_hash": "0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a", "proof": 888273, "transactions": [ { "amount": 1, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "0" } ] } ``` ## Step 14: Transactions are great! As our mining algorithm seems to be working fine, let's create a new transaction, to be stored in a fresh mined block. To do that in ### Postman 1. Click on the _new transaction_ request in the left sidebar. 2. Click on the _GET_ button with the small arrow pointing down. 3. Select _POST_ from the drop-down list. 4. In the navbar below the text field, select _Body_ 5. and then mark the _raw_ option. 6. You should now be provided with an editor like text area, and another drop-down menu next to the _binary_ option, where _Text_ is currently selected. Select _JSON (application/json)_ from this list. 7. Now type in the following into the text area. ```json { "sender": "your-node-address", "recipient": "another-node-address", "amount": 212 } ``` ### cURL Just execute `curl -X POST -H "Content-Type: application/json" -d '{"sender": "your-node-address", "recipient": "another-node-address", "amount": 212}' "http://localhost:5000/transactions/add"` in a terminal window. ### In both cases Replace `your-node-address` with the _recipient_ address from you mining request, as this is your node address. You can also select any other 32 digit hexadezimal number, for now. Furthermore replace `another-node-address` with a random 32 digit hexadezimal number for now, as we currently don't have any other nodes. Adjust the `amount` to your liking. And **voilà**! You have registered your first transaction! ## Step 15: The Chain... So let's inspect our chain! If you're using ### Postman Click on the _get whole blockchain_ request in the left sidebar and simply enter `http://localhost:5000/blockchain` in the `Enter request URL` text field, as _GET_ should be preselected. If not, please change it to the _GET_ option. ### cURL just execute `curl -i -H "Content-Type: application/json" -X GET http://localhost:5000/blockchain` in a terminal window. ### Either way you should get your whole blockchain in form of a JSON-Object. In my case, my blockchain looks like this, after mining 2 times, adding 3 transactions and mining another block: ```json { "chain": [ { "index": 1, "previous_hash": "1", "proof": 100, "timestamp": 1515156902.4502413, "transactions": [] }, { "index": 2, "previous_hash": "0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a", "proof": 888273, "timestamp": 1515156913.2686973, "transactions": [ { "amount": 1, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "0" } ] }, { "index": 3, "previous_hash": "1d2ae4a41f4a82ce6f04944e8227bf9c4d951d560f8763b910d7314634dfe09c", "proof": 1156297, "timestamp": 1515158367.3596537, "transactions": [ { "amount": 212, "recipient": "d4ee26eee15148ee92c6cd394edd974e", "sender": "491002ea048a42609d967027cc46a07b" }, { "amount": 212, "recipient": "5654c5654e1b551a65e15f5e4651c156", "sender": "491002ea048a42609d967027cc46a07b" }, { "amount": 111, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "5654c5654e1b551a65e15f5e4651c156" }, { "amount": 1, "recipient": "491002ea048a42609d967027cc46a07b", "sender": "0" } ] } ], "length": 3 } ``` # Decentralizing it Ok, so we got a blockchain, that's working fine and we can interact with it. But one very important thing is still missing: **Decentralization**. This is a core element of the blockchain idea. First off by decentralizing the whole thing, safety and integrity of the blockchain is guaranteed, as a change in the blockchain will be recognized, by the other nodes, as they also have a copy of the blockchain, and discarded. The second reason is that we somehow have to make sense of our transactions. For this we need other nodes and why shouldn't they contribute to our network, by being a part of the blockchain system?! But we still have a conflict there: What if a node has a blockchain that differs from all the others? For our simple blockchain we will always make the **longest valid** blockchain authorative. ## Step 16: Someone out there?! But first things first. To get started, we first have to implement other nodes into our system. To accomplish this task, we have to adjust a few things in our API. First off, we are going to implement some new endpoints: 1. `/nodes/add` to add new nodes in form of a list of URLs 2. `/nodes/resolve` to resolve the conflict we discussed previously by using a consensus algorithm. To do this, we have to modify our Blockchain class first: ```python [...] from urllib.parse import urlparse class MyBlockChain(object): def __init__(self): [...] self.nodes = set() def add_node(self, address): """ Register a new node :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000' :return: None """ node_url = urlparse(address) self.nodes.add(node_url.netloc) ``` ## Step 17: We need Consensus To resolve the conflict of differing blockchains between the nodes, we are going to implement a consensus algorithm. As we discussed earlier, we are always utilizing the longest valid blockchain. First we are implementing a function that validates a blockchain: ```python [...] import requests class MyBlockChain(object) [...] def validate_blockchain(self, test_chain): """ Evaluate, whether a blockchain is valid :param chain: <list> The blockchain that shall be tested :return: <bool> Returns true if the blockchain is valid """ last_block = test_chain[0] current_index = 1 while current_index < len(test_chain): block = test_chain[current_index] # Determine, whether the hash is correct if block['previous_hash'] != self.hash(last_block): return False # Determine, wheter the proof of work is correct if not self.validate_proof(last_block['proof'], block['proof']): return False last_block = block current_index += 1 return True ``` Now we just have to run every blockchain in our surrounding network through this consensus algorithm: ```python [...] class MyBlockChain(object) [...] def resolve(self): """ This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously. :return: <bool> Returns true, if our chain was substituted with an updated version """ surrounding_nodes = self.nodes updated_chain = None # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain max_length = len(self.blockchain) # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain. for node_iterator in surrounding_nodes: response = requests.get(f'http://{node_iterator}/blockchain') if response.status_code == 200: length = response.json()['length'] chain_iterator = response.json()['chain'] if length > max_length and self.validate_blockchain(chain_iterator): max_length = length updated_chain = chain_iterator # If we found a new blockchain, replace our current blockchain with the new one if updated_chain: self.blockchain = updated_chain return True return False ``` Now we just have to register our new functions as new endpoints in the API: ```python @app.route('/nodes/add', methods=['POST']) def add_nodes(): values = request.get_json() nodes = values.get('nodes') if nodes is None: return "You didn't post a valid list of nodes. Please double check your input!", 400 for node in nodes: myblockchain.add_node(node) response = { 'message': 'All of your specified nodes have been added to the network!', 'total_nodes': list(myblockchain.nodes), } return jsonify(response), 201 @app.route('/nodes/resolve', methods=['GET']) def consensus(): replaced = myblockchain.resolve() if replaced: response = { 'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.', 'new_chain': myblockchain.blockchain } else: response = { 'message': 'The blockchain of this node is already the longest valid chain within the network.', 'chain': myblockchain.blockchain } return jsonify(response), 200 ``` ## Step 18: Friends are great. Even if they're virtual... To test our decentralization algorithms, either grab some friends, to run some nodes for you, or just run the same program on different ports, so you would have to start up an instance of our blockchain-program, then change to port to 5001 for example, save, fire up an instance of this _modified_ program, change the port to 5002, etc. ## Step 19: Add them to your friends list If you got some instances, you just have to register them. To do this, simply send a `POST` request with the following content ```json { "nodes": ["http://[ip-of-another-node-or-127.0.0.1-for-your-local-machine]:[the-port-number]"] } ``` to `http://[the-node-ip-you-want-to-register-it-to]:[port]/nodes/add` ## Step 20: Consensus check After that try to mine some blocks and even add some transactions on let's say node 2 and then run `http://[a-node-ip]:[port]/nodes/resolve` on let's say node 1. The consensus algorithm should step into action and update the blockchain of node 1. # The whole thang I keep my promises ```python import hashlib import json import requests from time import time from uuid import uuid4 from textwrap import dedent from flask import Flask, jsonify, request from urllib.parse import urlparse class MyBlockChain(object): def __init__(self): self.blockchain = [] self.transactions = [] # Creation of the mentioned genesis block self.create_new_block(previous_hash=1, proof=100) self.nodes = set() def create_new_block(self, proof, previous_hash=None): """ Creates a new block and adds it to the blockchain :param proof: <int> This is generated by the proof of work algorithm :param previous_hash: (Optional) <str> Hash of the preleading Block :return: <dict> Return the new block """ new_block = { 'index': len(self.blockchain) + 1, 'timestamp': time(), 'transactions': self.transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.blockchain[-1]), } # As all pending transactions have been processed and added to the block, the list can be resetted self.transactions = [] # Add the new block to the blockchain self.blockchain.append(new_block) return new_block def create_new_transaction(self, sender, recipient, amount): """ This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions. :param sender: <str> Sender's address :param recipient: <str> Recipient's address :param amount: <int> Amount to be transferred :return: <int> This is the index of the block that will contain this transaction """ self.transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1 @staticmethod def hash(block): """ This function hashes the block using the SHA-256 hash algorithm The function is given a block and returns a string, consisting of the hash :param block: <dict> Block :return: <str> """ # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes block_sorted = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_sorted).hexdigest() @property def last_block(self): return self.blockchain[-1] def pow(self, last_proof): """ Simple PoW Algorithm: - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof. :param last_proof: <int> :return: <int> """ current_proof = 0 while self.validate_proof(last_proof, current_proof) is False: current_proof += 1 return current_proof @staticmethod def validate_proof(last_proof, current_proof): """ Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes. :param last_proof: <int> Previous Proof Number :param current_proof: <int> Current Proof Number :return: <bool> """ possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest() return possible_hash[:5] == "00000" def add_node(self, address): """ Register a new node :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000' :return: None """ node_url = urlparse(address) self.nodes.add(node_url.netloc) def validate_blockchain(self, test_chain): """ Evaluate, whether a blockchain is valid :param chain: <list> The blockchain that shall be tested :return: <bool> Returns true if the blockchain is valid """ last_block = test_chain[0] current_index = 1 while current_index < len(test_chain): block = test_chain[current_index] # Determine, whether the hash is correct if block['previous_hash'] != self.hash(last_block): return False # Determine, wheter the proof of work is correct if not self.validate_proof(last_block['proof'], block['proof']): return False last_block = block current_index += 1 return True def resolve(self): """ This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously. :return: <bool> Returns true, if our chain was substituted with an updated version """ surrounding_nodes = self.nodes updated_chain = None # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain max_length = len(self.blockchain) # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain. for node_iterator in surrounding_nodes: response = requests.get(f'http://{node_iterator}/blockchain') if response.status_code == 200: length = response.json()['length'] chain_iterator = response.json()['chain'] if length > max_length and self.validate_blockchain(chain_iterator): max_length = length updated_chain = chain_iterator # If we found a new blockchain, replace our current blockchain with the new one if updated_chain: self.blockchain = updated_chain return True return False app = Flask(__name__) node_identifier = str(uuid4()).replace('-', '') myblockchain = MyBlockChain() @app.route('/blockchain', methods=['GET']) def get_full_chain(): output = { 'chain': myblockchain.blockchain, 'length': len(myblockchain.blockchain), } return jsonify(output), 200 @app.route('/mining', methods=['GET']) def mining(): # Calculate the new proof by using our PoW algorithm last_block = myblockchain.last_block last_proof = last_block['proof'] proof = myblockchain.pow(last_proof) # For finding/mining the proof, the miner is granted a reward # The sender is nobody, as this coin is coming out of the void myblockchain.create_new_transaction( sender="0", recipient=node_identifier, amount=1, ) # Add the new created block to the chain previous_hash = myblockchain.hash(last_block) newblock = myblockchain.create_new_block(proof, previous_hash) output = { 'message': "A new block was mined", 'index': newblock['index'], 'transactions': newblock['transactions'], 'proof': newblock['proof'], 'previous_hash': newblock['previous_hash'], } return jsonify(output), 200 @app.route('/transactions/add', methods=['POST']) def add_transaction(): values = request.get_json() # The POST request has to have the following required fields required = ['sender', 'recipient', 'amount'] if not all(k in values for k in required): return 'There are values missing', 400 # Adds a new transaction by utilizing our function index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount']) output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'} return jsonify(output), 201 @app.route('/nodes/add', methods=['POST']) def add_nodes(): values = request.get_json() nodes = values.get('nodes') if nodes is None: return "You didn't post a valid list of nodes. Please double check your input!", 400 for node in nodes: myblockchain.add_node(node) response = { 'message': 'All of your specified nodes have been added to the network!', 'total_nodes': list(myblockchain.nodes), } return jsonify(response), 201 @app.route('/nodes/resolve', methods=['GET']) def consensus(): replaced = myblockchain.resolve() if replaced: response = { 'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.', 'new_chain': myblockchain.blockchain } else: response = { 'message': 'The blockchain of this node is already the longest valid chain within the network.', 'chain': myblockchain.blockchain } return jsonify(response), 200 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` # Final thoughts And there you have it! Your very own blockchain. Wasn't very hard, was it? I sincerely hope you had fun thorughout this tutorial and were able to understand the concept and system behind it better. If you have any questions, please ask them in the comments and I'll try my best to answer them. # The obligatory begging As this whole tutorial took me over 2 days to finish, I would love to see a lot of comments and feedback under this post. Also if you find any typos, grammar mistakes, etc. and care to tell me, i would be mor than happy about it, as English is not my native language. So please excuse any mistakes I made. I tried my very best. Of course please upvote, if you worship my effort to enrich the community, and if you want to see more such content, consider following me. I wish you only the best - See ya!
json metadata{"tags":["steemit","blockchain","trevonjb","cryptocurrency","upvoteforupvote"],"links":["https://www.python.org/downloads/windows/","https://en.wikipedia.org/wiki/Integrated_development_environment","https://www.jetbrains.com/pycharm","https://www.getpostman.com/","https://curl.haxx.se/","https://en.wikipedia.org/wiki/SHA-2","https://en.wikipedia.org/wiki/Proof-of-work_system"],"app":"steemit/0.1","format":"markdown"}
parent author
parent permlinksteemit
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
titleCreate your own blockchain & cryptocurrency! - understand blockchains by creating one in python - no knowledge required
Transaction InfoBlock #18742267/Trx 0db3d5121f95452bf55e53ad31c21e9b92ec940b
View Raw JSON Data
{
  "block": 18742267,
  "op": [
    "comment",
    {
      "author": "dustvoice",
      "body": "# What exactly is a blockchain?\n- How does a blockchain work?\n- What is Bitcoin or STEEM exactly?\n- How does a blockchain make sure of its correctness\n- What is **mining** exactly?\n\n**These are only some questions, probably many of you are asking yourselves. \nI'm here to provide you with kind of an unusual answer.\nMy goal is to help you undestand the whole system behind blockchains, by actually creating a small blockchain yourself!**\n\nWith the rise of cryptocurrencies and decentralized systems like Bitcoin or STEEM, many people want to really undestand, what this is all about. I will show you how the system works, by coding a blockchain from scratch in python with you. The guide will be mainly for Windows, but I will also add comments regarding Linux. You don't know a whole of python, to follow this guide, but it is advised to know the most basic basics.\n\n# Get ready\n## Setup Python and pip\nFirst off, we need to install Python 3.6+ along with pip, with which you can install python packages. \n- On **Linux**, you can install python, by simply typing `sudo apt-get install python3.6` into the terminal. If you encounter errors, please try `sudo apt-get update` and then try to execute the command again. If it still doesn't work, please search for installation instructions for your specific system on your preferred search engine.\n- On **Windows**,\n  1. first download the binary, that suits your system best, under the [official python download page for windows.](https://www.python.org/downloads/windows/). Make sure you grab at least the _version 3.6_ or higher.\n  2. Install the file you just downloaded. Make sure you check the option to install pip, when provided with an option to do so. If not, don't worry, it probably is enabled by default.\n\n## IDE or not?\nAs a next step, you want to decide, whether to utilize an [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) or not. An IDE is an environment, which supports you in the creation process of your application, by providing many features, with for example syntax highlighting, or code completion, to name just 2 possible features. My favorite IDE for Python development is probably PyCharm, which you can fetch from [this link.](https://www.jetbrains.com/pycharm) Setting up PyCharm on Windows is as simple, as downloading the executable installer and installing it with the provided setup utility. PyCharm is free tu use, as long as you use the Community Edition.\nYou can also use your coding notepad of choice. We will only work in one file, which you have to execute, so as long as your text-editing software is able to produce files with the ending `.py`, it will work fine.\n\n## Setup your workspace (PyCharm)\nIf you decided to use PyCharm, simply open it up and click on _Create Project_ in the popup dialogue. In the next dialogue you want to specify your project's name. I chose to use _MyBlockChain_ as my project name. Finally click on _create_ in the bottom right corner. On your left hand side, you're now provided with a file tree. \n1. Right-Click on the folder which consists of your project's name, in my case _MyBlockChain_\n2. Go to _new_ \n3. Finally click on _Python File_ and\n4. Define a Filename. I chose `MyBlockChain.py` as my filename.\n\n## Create your file (Simple Text Editor)\nIf you use a simple text editor, just create a file anywhere you like with the file extension `.py`. In my case I chose to use the filename `MyBlockChain.py`.\n\n## Install the needed packages\n### PyCharm\nIn PyCharm you can install packages very easily and add them to your project:\n1. Make sure, you have your project open\n2. Go to _File_ -> _Settings_ -> _Project: [your project name]_ -> _Project Interpreter_\n3. Then click on the green plus symbol.\n4. In the search field type in _Flask_ first. Select the first entry, which simply says _Flask_. Then click on Install Package in the bottom left corner.\n5. Do the same thing for _Requests_.\n### Pip\nIf you chose not to use PyCharm, you simply need to open up the terminal on linux or the command prompt, or PowerShell on Windows _(simply press **Windows+R** and type in cmd)_ and then execute `pip install Flask==0.12.2 requests==2.18.4 `. If this gives you an error, please double check that you have _pip_ installed. If the problem still occurs, please troubleshoot the error message using google, as there are too many possibilities, what the error could be caused by, for me to discuss every one of them here.\n\n## Getting a HTTP-Client\nYou will also need a HTTP-Client, as we need to make `GET` and `POST` requests to our Flask instance, at some Point in time. Mainly, there are two options - [_Postman_](https://www.getpostman.com/) or [_cURL_](https://curl.haxx.se/). I highly recommend _Postman_, as it is easy and intuitive to use, but if you just want a simple and quick solution, without having to register for an account, just use _cURL_. Online solutions, probably won't work, as the webserver you are going to be trying to access, is just on your local machine. \n\n## Just gimme the source code!\nIf you just want the source code and don't want to follow my instructions, please scroll down, to the very end of this post, where I will add the source code in its complete beauty.\n\n# The Blockchain - Your Blockchain\n## Step 1: Creating a simplistic Blockchain\nA block chain is basically a chain of blocks that are linked together in some way, as you have already figured. In this case, every block contains a hash of the previous block. A hash is a hexadecimal number that is determined by a specific algorithm. Imagine a hash being a digital fingerprint of an item. A good hash algorithm will never return the same hash for two different items, so every hash is individual. In our case we will be using the [_SHA-256_](https://en.wikipedia.org/wiki/SHA-2) algorithm. Furthermore the hash algorithm is not reversible, so you can't determine the object, by having its hash, but you can always apply the hash algorithm on the object, to get its hash. As every item has the hash of its previous item, the blockchain is protected against violation, as one would have to change every following block, as the hash changes with every change, as two different items can't have the same hash.\n### The Blockchain class\nOur Blockchain class basically consists of a constructor and some functions. In the constructor, we will create two empty lists - one to store our blockchain in and another, for our transactions. As for now, our class will have several functions:\n- A function to create new blocks\n- A function to create new transactions\n- A function, which hashes a block\n- A function to fetch the last block\nThe python template looks like this:\n```python\nclass MyBlockChain(object):\n    def __init__(self):\n        self.blockchain = []\n        self.transactions = []\n        \n    def create_new_block(self):\n        # This function creates a new block and appends it to the chain\n        pass\n    \n    def create_new_transaction(self):\n        # This function creates a new transaction and adds it to the list of transactions\n        pass\n    \n    @staticmethod\n    def hash(block):\n        # This method hashes the passed block\n        pass\n\n    @property\n    def last_block(self):\n        # This function returns the last block in the chain\n        pass\n```\n## Step 2: The blocks\nAs described earlier, a blockchain consists of blocks. So I will cover them first.\nEach Block has 5 fields:\n- An index,\n- an Unix timestamp,\n- a list of transactions,\n- a proof,\n- and finally the hash of the previous block.\nJust to clarify things, here is an example of a block\n```json\nexample_block = {\n    'index': 5,\n    'timestamp': 1515110045.123456,\n    'transactions': \n    [\n        {\n            'sender': \"154d8554f9541e12354e1234f512a001\",\n            'recipient': \"8654e21254c6512a51bce156542d1e5c\",\n            'amount': 212,\n        }\n    ],\n    'proof': 488612354568,\n    'previous_hash': \"c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e\"\n}\n```\n## Step 3: Hashing it\nAs every block needs the hash of the previous block, we need a function, that calculates the hash of a block. To accomplish this, we simply modify our empty `hash` function\n```python\nimport hashlib\nimport json\n\nclass MyBlockChain(object):\n    [...]\n    @staticmethod\n    def hash(block):\n        \"\"\"\n        This function hashes the block using the SHA-256 hash algorithm\n        The function is given a block and returns a string, consisting of the hash\n        :param block: <dict> Block\n        :return: <str>\n        \"\"\"\n\n        # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes\n        block_sorted = json.dumps(block, sort_keys=True).encode()\n        return hashlib.sha256(block_sorted).hexdigest()\n```\n## Step 4: Transactions\nOur `create_new_transaction` method is responsible for adding new transactions to the `transactions` list, which will then be stored inside a block. The whole function is pretty self explanatory. But first we need a function to return the last block of the chain, as we will calculate the new index, at which the transaction will be stored, by increasing the index of the last block by 1\n```python\nclass MyBlockChain(object):\n    [...]\n    @property\n    def last_block(self):\n        return self.blockchain[-1]\n```\nNow we can fill out the `create_new_transaction` function\n```python\nclass MyBlockChain(object):\n    [...]\n    def create_new_transaction(self, sender, recipient, amount):\n        \"\"\"\n        This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions.\n        \n        :param sender: <str> Sender's address\n        :param recipient: <str> Recipient's address\n        :param amount: <int> Amount to be transferred\n        :return: <int> This is the index of the block that will contain this transaction\n        \"\"\"\n\n        self.transactions.append({\n            'sender': sender,\n            'recipient': recipient,\n            'amount': amount,\n        })\n\n        return self.last_block['index'] + 1\n```\n## Step 5: Creating new Blocks\nBy now we almost have everything at our hands, what we need in order to make a new block. The only thing missing is the _proof_ field. As this is a little harder to understand, I will explain it later. \nBut we still have one problem - if every block has the hash of the previous block, what shall we do with our first block, as there is no previous block for us to hash. \nThis first block is called the _genesis_ block.\n```python\nimport hashlib\nimport json\nfrom time import time\n\nclass MyBlockChain(object):\n    def __init__(self):\n        self.blockchain = []\n        self.transactions = []\n\n        # Creation of the mentioned genesis block\n        self.create_new_block(previous_hash=1, proof=100)\n\n    def create_new_block(self, proof, previous_hash=None):\n        \"\"\"\n        Creates a new block and adds it to the blockchain\n        :param proof: <int> This is generated by the proof of work algorithm\n        :param previous_hash: (Optional) <str> Hash of the preleading Block\n        :return: <dict> Return the new block\n        \"\"\"\n\n        new_block = {\n            'index': len(self.blockchain) + 1,\n            'timestamp': time(),\n            'transactions': self.transactions,\n            'proof': proof,\n            'previous_hash': previous_hash or self.hash(self.blockchain[-1]),\n        }\n\n        # As all pending transactions have been processed and added to the block, the list can be resetted\n        self.transactions = []\n        \n        # Add the new block to the blockchain\n        self.blockchain.append(new_block)\n        return new_block\n```\n##  Step 6: What's up with the proof?!\n### The [Proof of Work (PoW) algorithm](https://en.wikipedia.org/wiki/Proof-of-work_system)\nThis system wants to **proof** that work has been done. Now a little bit less abstract. Basically we are searching for a number that matches a specific criteria. The thing is, for the system to work, the process of finding a number matching the criteria has to be **difficult**, but the verification process has to be **quick and easy**. This is how new blocks are created, or expressed in another, more commonly used term, _mined_.\n#### Still too abstract? Ok here is an example:\nWe are looking for a hash of a product of two integers that ends with a 1.\nSo the result of the multiplication of `a` and `b` gets hashed and has to end with a 1. If we set a to `a` static value, our algorithm will determine a value for `b`, for which this criteria is matched. \n```python\nfrom hashlib import sha256\na = 12\nb = 0  # We don't know what b has to be. It will be determined by the algorithm\nwhile sha256(f'{a*b}'.encode()).hexdigest()[-1] != \"1\":\n    b += 1\nprint(f'The solution is b = {b}')\n```\nThis example outputs\n```\nThe solution is b = 4\n```\nThis means that the hash of `12*4` ends with a 1\n```\nhash(48) = 98010bd9270f9b100b6214a21754fd33bdc8d41b2bc9f9dd16ff54d3c34ffd71\n```\nAs you can tell, the verification process doesn't need countless loops, until it finds a matching pair. You just have to run the hash algorithm once on the numbers and you can easily determine, whether the numbers match the criteria, or not.\n## Step 7: Implementing PoW\nFirstoff, we need a criteria, or commonly referred to as a rule. For now, our rule is that the hash has to have 5 leading zeroes, so `000005bc845e...` would be a valid result, but `000019ea76c4` would not. As the difficulty rises extremely, if we would require 6 leading zeros, the difficulty of our simple algorithm can be adjusted by changing the amount of leading zeroes required. This is the implementation in python:\n```python\n[...]\nfrom uuid import uuid4\n\nclass MyBlockChain(object):\n    [...]\n        \n    def pow(self, last_proof):\n        \"\"\"\n        Simple PoW Algorithm:\n         - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof.\n        :param last_proof: <int>\n        :return: <int>\n        \"\"\"\n        \n        current_proof = 0\n        while self.validate_proof(last_proof, current_proof) is False:\n            current_proof += 1\n\n        return current_proof\n\n    @staticmethod\n    def validate_proof(last_proof, current_proof):\n        \"\"\"\n        Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes.\n        :param last_proof: <int> Previous Proof Number\n        :param current_proof: <int> Current Proof Number\n        :return: <bool>\n        \"\"\"\n\n        possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest()\n        return possible_hash[:5] == \"00000\"\n```\n## Step 8: Interacting with our class\nNow we are able to create a blockchain. But we can't really interact with it, as we have only interacted with the functions and variables of our class.\nWe are going to use HTTP requests to interact with our blockchain. So let's set it up!\n# HTTP in the house!\nTo talk to our blockchain using Http requests, we need some help - which comes in the form of the _Flask Framework_. We will create and implement 3 basic methods for now:\n- `/blockchain` to retrieve the full blockchain\n- `/mining` to make our simple server mine a block\n- `/transactions/add` to add a new transaction to the blockchain.\n## Step 9: Flask\nFirst we need to implement Flask. Here is the code:\n```python\n[...]\nfrom textwrap import dedent\nfrom flask import Flask, jsonify, request\n\nclass MyBlockChain(object):\n    [...]\n    \napp = Flask(__name__)\nnode_identifier = str(uuid4()).replace('-', '')\n\nmyblockchain = MyBlockChain()\n\[email protected]('/blockchain', methods=['GET'])\ndef get_full_chain():\n    output = {\n        'chain': myblockchain.blockchain,\n        'length': len(myblockchain.blockchain),\n    }\n    return jsonify(output), 200\n\[email protected]('/mining', methods=['GET'])\ndef mining():\n    pass\[email protected]('/transactions/add', methods=['POST'])\ndef add_transaction():\n    pass\nif __name__ == '__main__':\n    app.run(host='0.0.0.0', port=5000)\n```\n## Step 10: Adding Transactions\nAs this is commonly the main task of a block chain and also required for a new block, I will cover this first. The user sends a _POST request_ to `/transactions/add` with a JSON object, containing all required fields. This is an example, for a possible, valid request:\n```json\n{\n \"sender\": \"154d8554f9541e12354e1234f512a001\",\n \"recipient\": \"8654e21254c6512a51bce156542d1e5c\",\n \"amount\": 212\n}\n```\nAs you can see, a request has three fields:\n- A _sender_ field, with the sender id,\n- a _recipient_ field, with the recipient id\n- and an amount, which defines how many units are to be transferred\nNow we just need to implement this function\n```python\n[...]\n\[email protected]('/transactions/add', methods=['POST'])\ndef add_transaction():\n    values = request.get_json()\n\n    # The POST request has to have the following required fields\n    required = ['sender', 'recipient', 'amount']\n    if not all(k in values for k in required):\n        return 'There are values missing', 400\n\n    # Adds a new transaction by utilizing our function\n    index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount'])\n\n    output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'}\n    return jsonify(output), 201\n```\nThis function simply calls the `create_new_transaction` method with the parameters of the POST request\n## Step 11: Setup your mines\nAs discussed earlier, future blocks have to be mined. If a new block is found/mined, all pending transactions are added to this block. To 'mine' a new block, our function hast to do three things\n1. Calculate the proof\n2. Reward the miner with a specific amount of coins (in our example 1 coin)\n3. Add the new mined block to the blockchain\n_(The fact that the recipient is our current node, will make more sense, as we will talk about decentralization later on.)_\n```python\[email protected]('/mining', methods=['GET'])\ndef mining():\n    # Calculate the new proof by using our PoW algorithm\n    last_block = myblockchain.last_block\n    last_proof = last_block['proof']\n    proof = myblockchain.pow(last_proof)\n\n    # For finding/mining the proof, the miner is granted a reward\n    # The sender is nobody, as this coin is coming out of the void\n    myblockchain.create_new_transaction(\n        sender=\"0\",\n        recipient=node_identifier,\n        amount=1,\n    )\n\n    # Add the new created block to the chain\n    previous_hash = myblockchain.hash(last_block)\n    newblock = myblockchain.create_new_block(proof, previous_hash)\n\n    output = {\n        'message': \"A new block was mined\",\n        'index': newblock['index'],\n        'transactions': newblock['transactions'],\n        'proof': newblock['proof'],\n        'previous_hash': newblock['previous_hash'],\n    }\n    return jsonify(output), 200\n```\n# Hello World!\nNow, **finally** we will be interacting with our blockchain API. Grab your HTTP client of choice and get going! I will explain the procedure for Postman and cURL.\n## Step 12: Start up the chain\nFirst off fire up your server. \nIn PyCharm simply click on _Run_ -> _Run..._ and select _[your filename].py_ as the file to run, in my case _myblockchain.py_.\nIf you chose to use a simple python file without an IDE, fire up a terminal or command prompt window inside the directory your file is located in and execute the following command\n```\npython blockchain.py\n```\nas a result you will see something similar to this\n```\n$ python blockchain.py\n* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n```\n**Note that you may be prompted with a dialogue of your firewall. Just accept it.**\n## Step 13: Mining it all!\nOk let's try the most exciting thing first, **mining**. I'm sure you can't wait to mine your first block, so let's do it!\nAs you can see in the code\n```python\n[...]\[email protected]('/mining', methods=['GET'])\ndef mining():\n    [...]\n```\nwe will be interacting with the `mining` part of our API through `GET` requests. This makes sense, as our only goal with this part of the API is, to mine a new block. We don't have to pass anything to the function at all, so a `GET` request is the way to go.\n### Postman\nIf you chose to use Postman, here is a quick tutorial on how to make a post request. \n1. First you have to register for an account, if you haven't already done that\n2. and login after that. \n3. If you are logged in, you shoudl be provided with several options such as _Request_, _Collection_, _Environment_.\n4. You could simply use the option _Request_, but to keep things organized, we are going to select the _Collection_ option. \n5. After that simply choose a name for your collection, in my case I'm using _MyBlockChain_ as my name.\n6. Now click on the _New_ Button, located in the top left corner and select _Request_ this time. We are now going to be creating 3 requests.\n7. The first request is going to be our _mining_ request, second is a _new transaction_ request and finally we will have a _get whole blockchain_ request. Of course you can customize the request names as you like. \n8. **Make sure, as you create these 3 requests, that you select our newly created Collection in the bottom section of the dialogue!**\n9. Now click on our Collection's folder in the left sidebar. You should see your 3 newly created requests. Select the _mining_ request first.\n10. On the right you are now provided with an interface. As you can see by the selected item from the dropdown box, left to the text field, a `GET` request is the standard request type, so we don't have to change that yet. \n11. In the text field `Enter request URL` we are now going to enter the `mining` URL of our API, so enter `http://localhost:5000/mining` as the request URL.\n### cURL\nIf you chose to use cURL as your HTTP client, simply type `curl -i -H \"Content-Type: application/json\" -X GET http://localhost:5000/mining` in a terminal window\n### Either way\nWith both methods you should see something similar to this as a result\n```json\n{\n    \"index\": 2,\n    \"message\": \"New Block Forged\",\n    \"previous_hash\": \"0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a\",\n    \"proof\": 888273,\n    \"transactions\": [\n        {\n            \"amount\": 1,\n            \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n            \"sender\": \"0\"\n        }\n    ]\n}\n```\n## Step 14: Transactions are great!\nAs our mining algorithm seems to be working fine, let's create a new transaction, to be stored in a fresh mined block. To do that in\n### Postman\n1. Click on the _new transaction_ request in the left sidebar.\n2. Click on the _GET_ button with the small arrow pointing down.\n3. Select _POST_ from the drop-down list.\n4. In the navbar below the text field, select _Body_ \n5. and then mark the _raw_ option.\n6. You should now be provided with an editor like text area, and another drop-down menu next to the _binary_ option, where _Text_ is currently selected. Select _JSON (application/json)_ from this list.\n7. Now type in the following into the text area.\n```json\n{\n \"sender\": \"your-node-address\",\n \"recipient\": \"another-node-address\",\n \"amount\": 212\n}\n```\n### cURL\nJust execute `curl -X POST -H \"Content-Type: application/json\" -d '{\"sender\": \"your-node-address\", \"recipient\": \"another-node-address\", \"amount\": 212}' \"http://localhost:5000/transactions/add\"` in a terminal window.\n### In both cases\nReplace `your-node-address` with the _recipient_ address from you mining request, as this is your node address. You can also select any other 32 digit hexadezimal number, for now. Furthermore replace `another-node-address` with a random 32 digit hexadezimal number for now, as we currently don't have any other nodes.\nAdjust the `amount` to your liking.\nAnd **voilà**! You have registered your first transaction!\n## Step 15: The Chain...\nSo let's inspect our chain! If you're using\n### Postman\nClick on the _get whole blockchain_ request in the left sidebar and simply enter `http://localhost:5000/blockchain` in the `Enter request URL` text field, as _GET_ should be preselected. If not, please change it to the _GET_ option.\n### cURL\njust execute  `curl -i -H \"Content-Type: application/json\" -X GET http://localhost:5000/blockchain` in a terminal window.\n### Either way\nyou should get your whole blockchain in form of a JSON-Object. In my case, my blockchain looks like this, after mining 2 times, adding 3 transactions and mining another block:\n```json\n{\n    \"chain\": [\n        {\n            \"index\": 1,\n            \"previous_hash\": \"1\",\n            \"proof\": 100,\n            \"timestamp\": 1515156902.4502413,\n            \"transactions\": []\n        },\n        {\n            \"index\": 2,\n            \"previous_hash\": \"0f9cb2f06100899cb31b85fef221e243d1088c0aa6840a568e58d4a27dbd186a\",\n            \"proof\": 888273,\n            \"timestamp\": 1515156913.2686973,\n            \"transactions\": [\n                {\n                    \"amount\": 1,\n                    \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n                    \"sender\": \"0\"\n                }\n            ]\n        },\n        {\n            \"index\": 3,\n            \"previous_hash\": \"1d2ae4a41f4a82ce6f04944e8227bf9c4d951d560f8763b910d7314634dfe09c\",\n            \"proof\": 1156297,\n            \"timestamp\": 1515158367.3596537,\n            \"transactions\": [\n                {\n                    \"amount\": 212,\n                    \"recipient\": \"d4ee26eee15148ee92c6cd394edd974e\",\n                    \"sender\": \"491002ea048a42609d967027cc46a07b\"\n                },\n                {\n                    \"amount\": 212,\n                    \"recipient\": \"5654c5654e1b551a65e15f5e4651c156\",\n                    \"sender\": \"491002ea048a42609d967027cc46a07b\"\n                },\n                {\n                    \"amount\": 111,\n                    \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n                    \"sender\": \"5654c5654e1b551a65e15f5e4651c156\"\n                },\n                {\n                    \"amount\": 1,\n                    \"recipient\": \"491002ea048a42609d967027cc46a07b\",\n                    \"sender\": \"0\"\n                }\n            ]\n        }\n    ],\n    \"length\": 3\n}\n```\n# Decentralizing it\nOk, so we got a blockchain, that's working fine and we can interact with it. But one very important thing is still missing: **Decentralization**. \nThis is a core element of the blockchain idea. \nFirst off by decentralizing the whole thing, safety and integrity of the blockchain is guaranteed, as a change in the blockchain will be recognized, by the other nodes, as they also have a copy of the blockchain, and discarded. \nThe second reason is that we somehow have to make sense of our transactions. For this we need other nodes and why shouldn't they contribute to our network, by being a part of the blockchain system?! \nBut we still have a conflict there: What if a node has a blockchain that differs from all the others? \nFor our simple blockchain we will always make the **longest valid** blockchain authorative.\n## Step 16: Someone out there?!\nBut first things first. \nTo get started, we first have to implement other nodes into our system.\nTo accomplish this task, we have to adjust a few things in our API. First off, we are going to implement some new endpoints:\n1. `/nodes/add` to add new nodes in form of a list of URLs\n2. `/nodes/resolve` to resolve the conflict we discussed previously by using a consensus algorithm.\nTo do this, we have to modify our Blockchain class first:\n```python\n[...]\nfrom urllib.parse import urlparse\n\nclass MyBlockChain(object):\n    def __init__(self):\n        [...]\n        self.nodes = set()\n\n    def add_node(self, address):\n        \"\"\"\n        Register a new node\n        :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000'\n        :return: None\n        \"\"\"\n\n        node_url = urlparse(address)\n        self.nodes.add(node_url.netloc)\n```\n## Step 17: We need Consensus\nTo resolve the conflict of differing blockchains between the nodes, we are going to implement a consensus algorithm. As we discussed earlier, we are always utilizing the longest valid blockchain.\nFirst we are implementing a function that validates a blockchain:\n```python\n[...]\nimport requests\n\nclass MyBlockChain(object)\n    [...]\n    \n    def validate_blockchain(self, test_chain):\n        \"\"\"\n        Evaluate, whether a blockchain is valid\n        :param chain: <list> The blockchain that shall be tested\n        :return: <bool> Returns true if the blockchain is valid\n        \"\"\"\n\n        last_block = test_chain[0]\n        current_index = 1\n\n        while current_index < len(test_chain):\n            block = test_chain[current_index]\n            \n            # Determine, whether the hash is correct\n            if block['previous_hash'] != self.hash(last_block):\n                return False\n\n            # Determine, wheter the proof of work is correct\n            if not self.validate_proof(last_block['proof'], block['proof']):\n                return False\n\n            last_block = block\n            current_index += 1\n\n        return True\n```\nNow we just have to run every blockchain in our surrounding network through this consensus algorithm:\n```python\n [...]\n\nclass MyBlockChain(object)\n    [...]\n    def resolve(self):\n        \"\"\"\n        This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously.\n        :return: <bool> Returns true, if our chain was substituted with an updated version\n        \"\"\"\n\n        surrounding_nodes = self.nodes\n        updated_chain = None\n\n        # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain\n        max_length = len(self.blockchain)\n\n        # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain.\n        for node_iterator in surrounding_nodes:\n            response = requests.get(f'http://{node_iterator}/blockchain')\n\n            if response.status_code == 200:\n                length = response.json()['length']\n                chain_iterator = response.json()['chain']\n\n                if length > max_length and self.validate_blockchain(chain_iterator):\n                    max_length = length\n                    updated_chain = chain_iterator\n\n        # If we found a new blockchain, replace our current blockchain with the new one\n        if updated_chain:\n            self.blockchain = updated_chain\n            return True\n\n        return False\n```\nNow we just have to register our new functions as new endpoints in the API:\n```python\[email protected]('/nodes/add', methods=['POST'])\ndef add_nodes():\n    values = request.get_json()\n\n    nodes = values.get('nodes')\n    if nodes is None:\n        return \"You didn't post a valid list of nodes. Please double check your input!\", 400\n\n    for node in nodes:\n        myblockchain.add_node(node)\n\n    response = {\n        'message': 'All of your specified nodes have been added to the network!',\n        'total_nodes': list(myblockchain.nodes),\n    }\n    return jsonify(response), 201\n\n\[email protected]('/nodes/resolve', methods=['GET'])\ndef consensus():\n    replaced = myblockchain.resolve()\n\n    if replaced:\n        response = {\n            'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.',\n            'new_chain': myblockchain.blockchain\n        }\n    else:\n        response = {\n            'message': 'The blockchain of this node is already the longest valid chain within the network.',\n            'chain': myblockchain.blockchain\n        }\n\n    return jsonify(response), 200\n```\n## Step 18: Friends are great. Even if they're virtual...\nTo test our decentralization algorithms, either grab some friends, to run some nodes for you, or just run the same program on different ports, so you would have to start up an instance of our blockchain-program, then change to port to 5001 for example, save, fire up an instance of this _modified_ program, change the port to 5002, etc. \n## Step 19: Add them to your friends list\nIf you got some instances, you just have to register them. To do this, simply send a `POST` request with the following content\n```json\n{\n    \"nodes\": [\"http://[ip-of-another-node-or-127.0.0.1-for-your-local-machine]:[the-port-number]\"]\n}\n```\nto `http://[the-node-ip-you-want-to-register-it-to]:[port]/nodes/add`\n## Step 20: Consensus check\nAfter that try to mine some blocks and even add some transactions on let's say node 2 and then run `http://[a-node-ip]:[port]/nodes/resolve` on let's say node 1. The consensus algorithm should step into action and update the blockchain of node 1.\n# The whole thang\nI keep my promises\n```python\nimport hashlib\nimport json\nimport requests\nfrom time import time\nfrom uuid import uuid4\nfrom textwrap import dedent\nfrom flask import Flask, jsonify, request\nfrom urllib.parse import urlparse\n\nclass MyBlockChain(object):\n    def __init__(self):\n        self.blockchain = []\n        self.transactions = []\n        \n        # Creation of the mentioned genesis block\n        self.create_new_block(previous_hash=1, proof=100)\n        \n        self.nodes = set()\n        \n    def create_new_block(self, proof, previous_hash=None):\n        \"\"\"\n        Creates a new block and adds it to the blockchain\n        :param proof: <int> This is generated by the proof of work algorithm\n        :param previous_hash: (Optional) <str> Hash of the preleading Block\n        :return: <dict> Return the new block\n        \"\"\"\n\n        new_block = {\n            'index': len(self.blockchain) + 1,\n            'timestamp': time(),\n            'transactions': self.transactions,\n            'proof': proof,\n            'previous_hash': previous_hash or self.hash(self.blockchain[-1]),\n        }\n\n        # As all pending transactions have been processed and added to the block, the list can be resetted\n        self.transactions = []\n        \n        # Add the new block to the blockchain\n        self.blockchain.append(new_block)\n        return new_block\n    \n    def create_new_transaction(self, sender, recipient, amount):\n        \"\"\"\n        This function creates a new transaction that will then be placed in a new block, alone or bundled together with other transactions.\n        \n        :param sender: <str> Sender's address\n        :param recipient: <str> Recipient's address\n        :param amount: <int> Amount to be transferred\n        :return: <int> This is the index of the block that will contain this transaction\n        \"\"\"\n\n        self.transactions.append({\n            'sender': sender,\n            'recipient': recipient,\n            'amount': amount,\n        })\n\n        return self.last_block['index'] + 1\n    \n    @staticmethod\n    def hash(block):\n        \"\"\"\n        This function hashes the block using the SHA-256 hash algorithm\n        The function is given a block and returns a string, consisting of the hash\n        :param block: <dict> Block\n        :return: <str>\n        \"\"\"\n\n        # As every change in an item changes the hash, we first have to do a little sort operation, or else we would get inconsistent hashes\n        block_sorted = json.dumps(block, sort_keys=True).encode()\n        return hashlib.sha256(block_sorted).hexdigest()\n\n    @property\n    def last_block(self):\n        return self.blockchain[-1]\n        \n    def pow(self, last_proof):\n        \"\"\"\n        Simple PoW Algorithm:\n         - Find a number y, so that hash(xy) starts with 5 zeroes. x is the last y aka last_proof. y is then the new proof.\n        :param last_proof: <int>\n        :return: <int>\n        \"\"\"\n        \n        current_proof = 0\n        while self.validate_proof(last_proof, current_proof) is False:\n            current_proof += 1\n\n        return current_proof\n\n    @staticmethod\n    def validate_proof(last_proof, current_proof):\n        \"\"\"\n        Returns, whether the hash of the lastproof and the current_proof contains 5 leading zeroes.\n        :param last_proof: <int> Previous Proof Number\n        :param current_proof: <int> Current Proof Number\n        :return: <bool>\n        \"\"\"\n\n        possible_hash = hashlib.sha256(f'{last_proof}{current_proof}'.encode()).hexdigest()\n        return possible_hash[:5] == \"00000\"\n        \n    def add_node(self, address):\n        \"\"\"\n        Register a new node\n        :param address: <str> This is the new node's address, for example 'http://192.168.1.112:5000'\n        :return: None\n        \"\"\"\n\n        node_url = urlparse(address)\n        self.nodes.add(node_url.netloc)\n        \n    def validate_blockchain(self, test_chain):\n        \"\"\"\n        Evaluate, whether a blockchain is valid\n        :param chain: <list> The blockchain that shall be tested\n        :return: <bool> Returns true if the blockchain is valid\n        \"\"\"\n\n        last_block = test_chain[0]\n        current_index = 1\n\n        while current_index < len(test_chain):\n            block = test_chain[current_index]\n            \n            # Determine, whether the hash is correct\n            if block['previous_hash'] != self.hash(last_block):\n                return False\n\n            # Determine, wheter the proof of work is correct\n            if not self.validate_proof(last_block['proof'], block['proof']):\n                return False\n\n            last_block = block\n            current_index += 1\n\n        return True\n        \n    def resolve(self):\n        \"\"\"\n        This algorithm resolves conflicts between our nodes. It is the consensus algorithm which I mentioned previously.\n        :return: <bool> Returns true, if our chain was substituted with an updated version\n        \"\"\"\n\n        surrounding_nodes = self.nodes\n        updated_chain = None\n\n        # If we follow our consensus algorithm description, we only want blockchains that are longer, than our current chain\n        max_length = len(self.blockchain)\n\n        # Iterate every surrounding nodes in our network through the consensus algorithm, which means checking if the node's blockchain is longer than our current blockchain and valid and set it as our new blockchain and continue checking, as there could be an even longer and valid blockchain.\n        for node_iterator in surrounding_nodes:\n            response = requests.get(f'http://{node_iterator}/blockchain')\n\n            if response.status_code == 200:\n                length = response.json()['length']\n                chain_iterator = response.json()['chain']\n\n                if length > max_length and self.validate_blockchain(chain_iterator):\n                    max_length = length\n                    updated_chain = chain_iterator\n\n        # If we found a new blockchain, replace our current blockchain with the new one\n        if updated_chain:\n            self.blockchain = updated_chain\n            return True\n\n        return False\n\napp = Flask(__name__)\nnode_identifier = str(uuid4()).replace('-', '')\n\nmyblockchain = MyBlockChain()\n\[email protected]('/blockchain', methods=['GET'])\ndef get_full_chain():\n    output = {\n        'chain': myblockchain.blockchain,\n        'length': len(myblockchain.blockchain),\n    }\n    return jsonify(output), 200\n\[email protected]('/mining', methods=['GET'])\ndef mining():\n    # Calculate the new proof by using our PoW algorithm\n    last_block = myblockchain.last_block\n    last_proof = last_block['proof']\n    proof = myblockchain.pow(last_proof)\n\n    # For finding/mining the proof, the miner is granted a reward\n    # The sender is nobody, as this coin is coming out of the void\n    myblockchain.create_new_transaction(\n        sender=\"0\",\n        recipient=node_identifier,\n        amount=1,\n    )\n\n    # Add the new created block to the chain\n    previous_hash = myblockchain.hash(last_block)\n    newblock = myblockchain.create_new_block(proof, previous_hash)\n\n    output = {\n        'message': \"A new block was mined\",\n        'index': newblock['index'],\n        'transactions': newblock['transactions'],\n        'proof': newblock['proof'],\n        'previous_hash': newblock['previous_hash'],\n    }\n    return jsonify(output), 200\n    \[email protected]('/transactions/add', methods=['POST'])\ndef add_transaction():\n    values = request.get_json()\n\n    # The POST request has to have the following required fields\n    required = ['sender', 'recipient', 'amount']\n    if not all(k in values for k in required):\n        return 'There are values missing', 400\n\n    # Adds a new transaction by utilizing our function\n    index = myblockchain.create_new_transaction(values['sender'], values['recipient'], values['amount'])\n\n    output = {'message': f'Your registered Transaction is going to be a part of the block with the index of {index}'}\n    return jsonify(output), 201\n    \[email protected]('/nodes/add', methods=['POST'])\ndef add_nodes():\n    values = request.get_json()\n\n    nodes = values.get('nodes')\n    if nodes is None:\n        return \"You didn't post a valid list of nodes. Please double check your input!\", 400\n\n    for node in nodes:\n        myblockchain.add_node(node)\n\n    response = {\n        'message': 'All of your specified nodes have been added to the network!',\n        'total_nodes': list(myblockchain.nodes),\n    }\n    return jsonify(response), 201\n\n\[email protected]('/nodes/resolve', methods=['GET'])\ndef consensus():\n    replaced = myblockchain.resolve()\n\n    if replaced:\n        response = {\n            'message': 'There was a longer valid chain within the network. The blockchain of this node has been replaced.',\n            'new_chain': myblockchain.blockchain\n        }\n    else:\n        response = {\n            'message': 'The blockchain of this node is already the longest valid chain within the network.',\n            'chain': myblockchain.blockchain\n        }\n\n    return jsonify(response), 200\n\nif __name__ == '__main__':\n    app.run(host='0.0.0.0', port=5000)\n```\n# Final thoughts\nAnd there you have it!\nYour very own blockchain. Wasn't very hard, was it?\nI sincerely hope you had fun thorughout this tutorial and were able to understand the concept and system behind it better. If you have any questions, please ask them in the comments and I'll try my best to answer them.\n# The obligatory begging\nAs this whole tutorial took me over 2 days to finish, I would love to see a lot of comments and feedback under this post. Also if you find any typos, grammar mistakes, etc. and care to tell me, i would be mor than happy about it, as English is not my native language. So please excuse any mistakes I made. I tried my very best.\nOf course please upvote, if you worship my effort to enrich the community, and if you want to see more such content, consider following me. \nI wish you only the best - See ya!",
      "json_metadata": "{\"tags\":[\"steemit\",\"blockchain\",\"trevonjb\",\"cryptocurrency\",\"upvoteforupvote\"],\"links\":[\"https://www.python.org/downloads/windows/\",\"https://en.wikipedia.org/wiki/Integrated_development_environment\",\"https://www.jetbrains.com/pycharm\",\"https://www.getpostman.com/\",\"https://curl.haxx.se/\",\"https://en.wikipedia.org/wiki/SHA-2\",\"https://en.wikipedia.org/wiki/Proof-of-work_system\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
      "parent_author": "",
      "parent_permlink": "steemit",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "title": "Create your own blockchain & cryptocurrency! - understand blockchains by creating one in python - no knowledge required"
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T14:07:54",
  "trx_id": "0db3d5121f95452bf55e53ad31c21e9b92ec940b",
  "trx_in_block": 19,
  "virtual_op": 0
}
2018/01/06 14:03:00
authordustvoice
bodyMine is an interesting article too: https://steemit.com/steemit/@dustvoice/create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
json metadata{"tags":["resteem"],"links":["https://steemit.com/steemit/@dustvoice/create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required"],"app":"steemit/0.1"}
parent authorhursh
parent permlink7hpiuf-free-re-steem-to-all-my-steemit-friends
permlinkre-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t140259089z
title
Transaction InfoBlock #18742169/Trx 49d8a6cfd021d39d9a3788962c31a59305ec16e6
View Raw JSON Data
{
  "block": 18742169,
  "op": [
    "comment",
    {
      "author": "dustvoice",
      "body": "Mine is an interesting article too: https://steemit.com/steemit/@dustvoice/create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "json_metadata": "{\"tags\":[\"resteem\"],\"links\":[\"https://steemit.com/steemit/@dustvoice/create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required\"],\"app\":\"steemit/0.1\"}",
      "parent_author": "hursh",
      "parent_permlink": "7hpiuf-free-re-steem-to-all-my-steemit-friends",
      "permlink": "re-hursh-7hpiuf-free-re-steem-to-all-my-steemit-friends-20180106t140259089z",
      "title": ""
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T14:03:00",
  "trx_id": "49d8a6cfd021d39d9a3788962c31a59305ec16e6",
  "trx_in_block": 34,
  "virtual_op": 0
}
2018/01/06 13:10:48
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voterfitinfun
weight300 (3.00%)
Transaction InfoBlock #18741125/Trx f9e3d11de148b45c54a63835d10de34667e75cd1
View Raw JSON Data
{
  "block": 18741125,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "fitinfun",
      "weight": 300
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T13:10:48",
  "trx_id": "f9e3d11de148b45c54a63835d10de34667e75cd1",
  "trx_in_block": 23,
  "virtual_op": 0
}
2018/01/06 10:58:36
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
votermittymartz
weight10000 (100.00%)
Transaction InfoBlock #18738481/Trx d7b153bd5522159b49457e145f0588d42c1111b5
View Raw JSON Data
{
  "block": 18738481,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "mittymartz",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T10:58:36",
  "trx_id": "d7b153bd5522159b49457e145f0588d42c1111b5",
  "trx_in_block": 16,
  "virtual_op": 0
}
2018/01/06 10:39:09
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voterparaalttiredoks
weight10000 (100.00%)
Transaction InfoBlock #18738093/Trx ff9e3093663795f9f975e2057fbc8e7de5099ee4
View Raw JSON Data
{
  "block": 18738093,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "paraalttiredoks",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T10:39:09",
  "trx_id": "ff9e3093663795f9f975e2057fbc8e7de5099ee4",
  "trx_in_block": 30,
  "virtual_op": 0
}
2018/01/06 08:44:24
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
votervijaynag6
weight10000 (100.00%)
Transaction InfoBlock #18735798/Trx 8b4ece4f0f288e6daa923ece3fa31b97128bd29e
View Raw JSON Data
{
  "block": 18735798,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "vijaynag6",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T08:44:24",
  "trx_id": "8b4ece4f0f288e6daa923ece3fa31b97128bd29e",
  "trx_in_block": 0,
  "virtual_op": 0
}
2018/01/06 07:18:36
authordustvoice
permlinkcreate-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required
voteramit-negi
weight10000 (100.00%)
Transaction InfoBlock #18734084/Trx 008ed48e69b54855e68c1ec26258e3981b984ebd
View Raw JSON Data
{
  "block": 18734084,
  "op": [
    "vote",
    {
      "author": "dustvoice",
      "permlink": "create-your-own-blockchain-and-cryptocurrency-understand-blockchains-by-creating-one-in-python-no-knowledge-required",
      "voter": "amit-negi",
      "weight": 10000
    }
  ],
  "op_in_trx": 0,
  "timestamp": "2018-01-06T07:18:36",
  "trx_id": "008ed48e69b54855e68c1ec26258e3981b984ebd",
  "trx_in_block": 35,
  "virtual_op": 0
}

Account Metadata

POSTING JSON METADATA
profile{"profile_image":"https://cdn.steemitimages.com/DQmYdjT45r1aPnK4Cigvc5LK6Wjo1SDuhGS8LUb8YfzvwSa/crop_image.jpg","cover_image":"https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500","name":"DustVoice","website":"https://dustvoice.de","version":2}
JSON METADATA
profile{"profile_image":"https://s14.postimg.org/a0f3n4az5/Dust_Voice.png","cover_image":"https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500","name":"DustVoice","website":"http://dustvoice.de"}
{
  "posting_json_metadata": {
    "profile": {
      "profile_image": "https://cdn.steemitimages.com/DQmYdjT45r1aPnK4Cigvc5LK6Wjo1SDuhGS8LUb8YfzvwSa/crop_image.jpg",
      "cover_image": "https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500",
      "name": "DustVoice",
      "website": "https://dustvoice.de",
      "version": 2
    }
  },
  "json_metadata": {
    "profile": {
      "profile_image": "https://s14.postimg.org/a0f3n4az5/Dust_Voice.png",
      "cover_image": "https://pbs.twimg.com/profile_banners/720211137070022656/1475770438/1500x500",
      "name": "DustVoice",
      "website": "http://dustvoice.de"
    }
  }
}

Auth Keys

Owner
Single Signature
Public Keys
STM73fjp31DVRWU9tynHwLsQYYFqBfsB76iEdpJSFhSJsVTuKab491/1
Active
Single Signature
Public Keys
STM8fVSCYFindrWfyACRBjd3e6LRthpKDG47KPrw6n3Tg2zK3yG211/1
Posting
Single Signature
Public Keys
STM5XZRiDa7pe2QwkytkGamYZ1TtzBgKxDoWeDjVzP1oySuD9gLrK1/1
App Permissions
Memo
STM69fmSxgcza1TYkcSgtWYPvnKvuaWoDBovN7bq7vvyHYCubJ2z4
{
  "owner": {
    "account_auths": [],
    "key_auths": [
      [
        "STM73fjp31DVRWU9tynHwLsQYYFqBfsB76iEdpJSFhSJsVTuKab49",
        1
      ]
    ],
    "weight_threshold": 1
  },
  "active": {
    "account_auths": [],
    "key_auths": [
      [
        "STM8fVSCYFindrWfyACRBjd3e6LRthpKDG47KPrw6n3Tg2zK3yG21",
        1
      ]
    ],
    "weight_threshold": 1
  },
  "posting": {
    "account_auths": [
      [
        "dmania.app",
        1
      ]
    ],
    "key_auths": [
      [
        "STM5XZRiDa7pe2QwkytkGamYZ1TtzBgKxDoWeDjVzP1oySuD9gLrK",
        1
      ]
    ],
    "weight_threshold": 1
  },
  "memo": "STM69fmSxgcza1TYkcSgtWYPvnKvuaWoDBovN7bq7vvyHYCubJ2z4"
}

Witness Votes

0 / 30
No active witness votes.
[]