19 |
20 | {{ video.aggregate_likes }}
21 |
22 |
15 | Uploading video file is successful!
16 |
17 | {% endif %}
18 |
61 | ├── Chapter01 ├── altering_data_on_blockchain.py ├── falsify_message.py ├── linked_list.py ├── nelsonkey.pem ├── nelsonkey.pub ├── simple_blockchain.py ├── simple_proof_of_work.py ├── validate_message.py └── verify_message.py ├── Chapter02 └── my_first_smart_contract │ ├── build │ └── contracts │ │ ├── Donation.json │ │ └── Migrations.json │ ├── contracts │ ├── Migrations.sol │ └── donation.sol │ ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_donation.js │ └── truffle-config.js ├── Chapter03 ├── compiler.py ├── donation.vy ├── donation_call_hello_contract.vy └── hello.vy ├── Chapter04 ├── deploy_smart_contract_to_ganache.py ├── deploy_smart_contract_to_rinkeby.py ├── estimate_gas.py ├── extract_private_key.py ├── get_latest_nonce.py ├── play_with_smart_contract_in_ganache.py ├── play_with_smart_contract_in_rinkeby.py ├── send_money_ganache.py └── send_money_rinkeby.py ├── Chapter05 └── populus_tutorial │ ├── build │ └── contracts.json │ ├── contracts │ ├── Donation.vy │ ├── Greeter.vy │ └── Greeter2.vy │ ├── interact_smart_contract_in_ganache.py │ ├── interact_smart_contract_in_private_chain.py │ ├── project.json │ └── tests │ ├── __pycache__ │ ├── test_donation.cpython-36-PYTEST.pyc │ ├── test_greeter.cpython-36-PYTEST.pyc │ └── test_greeter2.cpython-36-PYTEST.pyc │ ├── test_donation.py │ ├── test_greeter.py │ └── test_greeter2.py ├── Chapter06 ├── voting_dapp │ ├── address.txt │ ├── client_address.txt │ ├── get_bytecode_from_smart_contract_address.py │ ├── simple_voting_client.py │ └── watch_simple_voting.py └── voting_project │ ├── 10_accounts.txt │ ├── build │ └── contracts.json │ ├── chains │ └── localblock │ │ ├── chain_data │ │ └── geth │ │ │ ├── chaindata │ │ │ ├── 000018.log │ │ │ ├── 000020.ldb │ │ │ ├── CURRENT │ │ │ ├── CURRENT.bak │ │ │ ├── LOG │ │ │ └── MANIFEST-000019 │ │ │ ├── lightchaindata │ │ │ ├── 000001.log │ │ │ ├── CURRENT │ │ │ ├── LOG │ │ │ └── MANIFEST-000000 │ │ │ ├── nodekey │ │ │ └── transactions.rlp │ │ ├── genesis.json │ │ ├── init_chain.sh │ │ ├── password │ │ └── run_chain.sh │ ├── create_10_accounts_on_private_chain.py │ ├── deploy_SmartVoting.py │ ├── distribute_money.py │ ├── get_bytecode_from_address.py │ ├── how_much_money_do_i_have.py │ └── project.json ├── Chapter07 ├── crash_course_qt_for_python │ ├── hello.py │ ├── hello_connect_param.py │ ├── hello_connect_signal_slot.py │ ├── hello_connect_simple.py │ ├── hello_custom_signal_slot.py │ ├── hello_horizontal_layout.py │ ├── hello_thread.py │ ├── hello_varieties.py │ ├── hello_vertical_horizontal_layout.py │ └── hello_vertical_layout.py ├── dapp │ ├── address.txt │ ├── fixtures.py │ └── twitter_dapp.py └── twitter_on_blockchain │ ├── build │ └── contracts.json │ ├── contracts │ └── TwitterOnBlockchain.vy │ ├── project.json │ └── tests │ └── test_twitter_on_blockchain.py ├── Chapter08 └── token_project │ ├── build │ └── contracts.json │ ├── chains │ └── localblock │ │ ├── genesis.json │ │ ├── init_chain.sh │ │ ├── password │ │ └── run_chain.sh │ ├── contracts │ ├── CrowdSaleToken.vy │ ├── ERC20Token.vy │ ├── SimpleToken.vy │ ├── SimpleTokenMint.vy │ └── StableCoin.vy │ ├── project.json │ └── tests │ ├── test_crowd_sale_token.py │ ├── test_erc20_token.py │ ├── test_simple_token.py │ └── test_stable_token.py ├── Chapter09 ├── advanced_course_qt │ ├── add_stretch.py │ ├── button_and_dialog.py │ ├── button_and_label.py │ ├── button_and_list.py │ ├── button_and_long_process.py │ ├── button_with_sizepolicy.py │ ├── combobox_and_label.py │ ├── create_grid_window.py │ ├── tabbed_window.py │ ├── test_button_and_dialog.py │ ├── test_button_and_label.py │ ├── test_button_and_list.py │ ├── test_button_and_long_process.py │ ├── test_combobox_and_label.py │ └── test_tabbed_window.py ├── chains │ ├── build │ │ └── contracts.json │ ├── contracts │ │ ├── ERC20Token.vy │ │ └── ERC20Token2.vy │ ├── localblock │ │ ├── genesis.json │ │ ├── init_chain.sh │ │ ├── password │ │ └── run_chain.sh │ ├── project.json │ └── registrar.json └── wallet │ ├── address.txt │ ├── blockchain.py │ ├── icons │ ├── ajax-loader.gif │ └── copy.svg │ ├── images │ ├── 427af7b53b8f56adf6f13932bb17c42ed2a53d04.png │ └── 6ad2ffd2e08bd73f5c50db60fdc82a58b0590b99.png │ ├── tests │ ├── test_account.py │ ├── test_send.py │ └── test_token.py │ ├── tools │ ├── identicon.py │ └── util.py │ ├── wallet.py │ ├── wallet_threads │ ├── balance_thread.py │ ├── send_thread.py │ └── send_token_thread.py │ └── wallet_widgets │ ├── account_widget.py │ ├── send_widget.py │ └── token_widget.py ├── Chapter10 ├── create_hash_from_content.py ├── hash_big_file.py ├── hash_directory.py ├── hello.txt ├── hello2.txt ├── hello3.txt ├── hello4.txt ├── hello_big.txt ├── merkle_dag.py ├── merkle_tree.py ├── sample_directory │ ├── hello.txt │ ├── hello2.txt │ ├── hello3.txt │ └── inner_directory │ │ └── hello4.txt └── test_merkle_dag_node.py ├── Chapter11 ├── add_directory.py ├── add_file.py ├── add_horoscope_predictions.py ├── add_image_file.py ├── cat.jpg ├── cat_cute_cat.py ├── construct_image_from_blocks.py ├── copy_in_mfs.py ├── crypto.proto ├── crypto_pb2.py ├── download_a_directory_of_cute_cat_picture.py ├── download_cute_cat_picture.py ├── exploring_mfs.py ├── generate_another_key.py ├── get_unicorn.py ├── get_unicorn_block.py ├── hello.txt ├── horoscope1.txt ├── horoscope2.txt ├── image_from_blocks.jpg ├── keys_list.py ├── list_blocks.py ├── merkledag.proto ├── merkledag_pb2.py ├── milada-vigerova-1284157-unsplash.jpg ├── mysite │ ├── README.md │ ├── img │ │ └── cat.jpg │ └── index.html ├── nude_picture.jpg ├── publish_horoscope1.py ├── publish_horoscope1_in_another_ipns.py ├── publish_horoscope2.py ├── publish_topic.py ├── removing_nude_picture.py ├── serialize_crypto_data.py ├── serialize_unicorn.py ├── subscribe_topic.py ├── unixfs.proto ├── unixfs_pb2.py └── unserialize_unicorn.py ├── Chapter12 ├── bootstrap_videos.py ├── check_bootstrap.py ├── decentralized_videos │ ├── decentralized_videos │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ ├── manage.py │ └── videos │ │ ├── admin.py │ │ ├── apps.py │ │ ├── models.py │ │ ├── templates │ │ └── videos │ │ │ ├── base.html │ │ │ ├── channel.html │ │ │ ├── index.html │ │ │ ├── upload.html │ │ │ └── video.html │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py └── videos_sharing_smart_contract │ ├── build │ └── contracts.json │ ├── contracts │ └── VideosSharing.vy │ ├── project.json │ ├── registrar.json │ └── tests │ └── test_videos_sharing.py ├── LICENSE └── README.md /Chapter01/altering_data_on_blockchain.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import json 3 | 4 | class Block: 5 | id = None 6 | history = None 7 | parent_id = None 8 | parent_hash = None 9 | 10 | block_A = Block() 11 | block_A.id = 1 12 | block_A.history = 'Nelson likes cat' 13 | 14 | block_B = Block() 15 | block_B.id = 2 16 | block_B.history = 'Marie likes dog' 17 | block_B.parent_id = block_A.id 18 | block_B.parent_hash = hashlib.sha256(json.dumps(block_A.__dict__).encode('utf-8')).hexdigest() 19 | 20 | block_C = Block() 21 | block_C.id = 3 22 | block_C.history = 'Marie likes dog' 23 | block_C.parent_id = block_B.id 24 | block_C.parent_hash = hashlib.sha256(json.dumps(block_B.__dict__).encode('utf-8')).hexdigest() 25 | 26 | print("Original parent hash in block C") 27 | print(block_C.parent_hash) 28 | print() 29 | 30 | print("Change data on block A") 31 | print() 32 | block_A.history = 'Nelson hates cat' 33 | block_B.parent_hash = hashlib.sha256(json.dumps(block_A.__dict__).encode('utf-8')).hexdigest() 34 | block_C.parent_hash = hashlib.sha256(json.dumps(block_B.__dict__).encode('utf-8')).hexdigest() 35 | 36 | print("New parent hash in block C which is different from original one") 37 | print(block_C.parent_hash) 38 | -------------------------------------------------------------------------------- /Chapter01/falsify_message.py: -------------------------------------------------------------------------------- 1 | from cryptography.hazmat.primitives import hashes 2 | from cryptography.hazmat.primitives.asymmetric import padding 3 | from cryptography.hazmat.backends import default_backend 4 | from cryptography.hazmat.primitives.asymmetric import rsa 5 | from cryptography.hazmat.primitives import serialization 6 | 7 | message = b'Nelson hates cat' 8 | signature = b'Fake Signature' 9 | 10 | with open("nelsonkey.pub", "rb") as key_file: 11 | public_key = serialization.load_pem_public_key( 12 | key_file.read(), 13 | backend=default_backend()) 14 | 15 | public_key.verify( 16 | signature, 17 | message, 18 | padding.PSS(mgf=padding.MGF1(hashes.SHA256()), 19 | salt_length=padding.PSS.MAX_LENGTH), 20 | hashes.SHA256()) 21 | -------------------------------------------------------------------------------- /Chapter01/linked_list.py: -------------------------------------------------------------------------------- 1 | class Block: 2 | id = None 3 | history = None 4 | parent_id = None 5 | 6 | block_A = Block() 7 | block_A.id = 1 8 | block_A.history = 'Nelson likes cat' 9 | 10 | block_B = Block() 11 | block_B.id = 2 12 | block_B.history = 'Marie likes dog' 13 | block_B.parent_id = block_A.id 14 | 15 | block_C = Block() 16 | block_C.id = 3 17 | block_C.history = 'Sky hates dog' 18 | block_C.parent_id = block_B.id 19 | -------------------------------------------------------------------------------- /Chapter01/nelsonkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQDI7EwiWGrMg/jTkp2AYMYHqNiXq3npC17MnkdSsSg8/GwluUPs 3 | 56WfbvFMf/lJGHHs2jsApDGSRw10kjQrdu+cJC61978t93utokltqAby1l/VV4oS 4 | miPQ0vfIU9PGTGP4ZZNEaAaNfdRRG7q5TgzwIs52iEVQwzhqr4JYgwiEqQIDAQAB 5 | AoGAMPXz74KgM8oM/nGB0+DBIOiyLvNoN7O/nBkNxEbLSWExcVfeB4LDR0CfqEaf 6 | FoLQcCkVq6hXNBAAZWGjONw4suMUPFAR7LyAyxsdevxnOsh0CVM2FapqCZ9DRjOl 7 | 4vFKpHtrnGCYb5s3L6aduOkP1JDRnypD4oj0BFCesg8E6KECQQDxwNg4/pFB+FFW 8 | hm2XKuXl2aHGBj/1zDueY0ZmF7OvToamILIZqiOykBl7HwiHTFTvcvYJ/KAWn8mw 9 | XPxrMMjVAkEA1MN5+Bqn9I0EUw/g+Ct5+yexGIePTsdHmVzcGVXCaZHfjX8UBJwU 10 | 1x2y/3O4GwbKtAsxDNajtV8wW/nPrKZ2hQJBAJaWkFlYQTU9r7TdAbDTOOdnHD0U 11 | sYyzjkOIBVcc1oGRwZAD98zCzX+yAR1PZGma46FQE/B+m13cZK7mDRncBo0CQH+5 12 | xcvivLc7vL/chXKWLwlOX6tZHfft/BaeP2daK3bS4oCALFVEGeK16pIeNwTKg/+n 13 | xE9vvyGPvmlIw5pi6D0CQQDKSV1VSWh2M7XIfxWnJqKd+qbr8x1IU0MJsPFmBwOW 14 | EwS111GZYpHqQ1bf12XaUZ92jEZ87DdXvcHmjxekpvig 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /Chapter01/nelsonkey.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI7EwiWGrMg/jTkp2AYMYHqNiX 3 | q3npC17MnkdSsSg8/GwluUPs56WfbvFMf/lJGHHs2jsApDGSRw10kjQrdu+cJC61 4 | 978t93utokltqAby1l/VV4oSmiPQ0vfIU9PGTGP4ZZNEaAaNfdRRG7q5TgzwIs52 5 | iEVQwzhqr4JYgwiEqQIDAQAB 6 | -----END PUBLIC KEY----- 7 | -------------------------------------------------------------------------------- /Chapter01/simple_blockchain.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import json 3 | 4 | class Block: 5 | id = None 6 | history = None 7 | parent_id = None 8 | parent_hash = None 9 | 10 | block_A = Block() 11 | block_A.id = 1 12 | block_A.history = 'Nelson likes cat' 13 | 14 | block_B = Block() 15 | block_B.id = 2 16 | block_B.history = 'Marie likes dog' 17 | block_B.parent_id = block_A.id 18 | block_B.parent_hash = hashlib.sha256(json.dumps(block_A.__dict__).encode('utf-8')).hexdigest() 19 | 20 | block_C = Block() 21 | block_C.id = 3 22 | block_C.history = 'Marie likes dog' 23 | block_C.parent_id = block_B.id 24 | block_C.parent_hash = hashlib.sha256(json.dumps(block_B.__dict__).encode('utf-8')).hexdigest() 25 | -------------------------------------------------------------------------------- /Chapter01/simple_proof_of_work.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | payload_string = '{"history": "Sky loves turtle", "parent_id": 3, "id": 4}' 4 | payload_bytes = bytes(payload_string, 'utf-8') 5 | for i in range(1000000): 6 | nonce = str(i).encode('utf-8') 7 | result = hashlib.sha256(payload_bytes + nonce).hexdigest() 8 | if result[0:5] == '00000': 9 | print("The answer to puzzle: " + str(i)) 10 | print("Input to hash is: " + payload_string + str(i)) 11 | print("Output hash which has 5 leading zeros: " + result) 12 | break 13 | 14 | -------------------------------------------------------------------------------- /Chapter01/validate_message.py: -------------------------------------------------------------------------------- 1 | from cryptography.hazmat.primitives import hashes 2 | from cryptography.hazmat.primitives.asymmetric import padding 3 | from cryptography.hazmat.backends import default_backend 4 | from cryptography.hazmat.primitives.asymmetric import rsa 5 | from cryptography.hazmat.primitives import serialization 6 | 7 | def fetch_public_key(user): 8 | with open(user.decode('ascii') + "key.pub", "rb") as key_file: 9 | public_key = serialization.load_pem_public_key( 10 | key_file.read(), 11 | backend=default_backend()) 12 | return public_key 13 | 14 | # Message coming from user 15 | message = b"Nelson likes cat" 16 | 17 | # Signature coming from user 18 | signature = b'7\xe1\xbe\xff\xa8\xe5\'{\xe7\x97w\xfa\x87c\x19\xf0T\xca\xcd\x13\xe0\x80\xa3<\xed\x8b\x1f\x98\x19f\xe4\x00S\xe4\xed \x99Q\x15\x93\xb3\xf1\xe0\\\x03\xbe`\x9ab\xdc+\x9a\xb9\x00\x19\xf4\xe0\xa4a\x17i0HD\xe6~\\\x952\xec5\x18I\xd8k&\x13\xdcY"\xb9o\xa9\xe0\xf2\xa7\x8e\t\xa1PF\xd0\x8a\x10p\xe8\xcd\xc3\xe6f\x93\x9a\xe0\x7f\xbb\xe2\xd6HVM:\xd1\xcfG\xf6\x98gm$\xdf^\xf4\xae\xe4\xd5\xea\xb5\xb4' 19 | 20 | user = message.split()[0].lower() 21 | # fetch public key from Nelson 22 | public_key = fetch_public_key(user) 23 | # … verify the message like before 24 | public_key.verify( 25 | signature, 26 | message, 27 | padding.PSS(mgf=padding.MGF1(hashes.SHA256()), 28 | salt_length=padding.PSS.MAX_LENGTH), 29 | hashes.SHA256()) 30 | -------------------------------------------------------------------------------- /Chapter01/verify_message.py: -------------------------------------------------------------------------------- 1 | from cryptography.hazmat.primitives import hashes 2 | from cryptography.hazmat.primitives.asymmetric import padding 3 | from cryptography.hazmat.backends import default_backend 4 | from cryptography.hazmat.primitives.asymmetric import rsa 5 | from cryptography.hazmat.primitives import serialization 6 | 7 | # Configuration 8 | GENERATE_PRIVATE_KEY = False 9 | DERIVE_PUBLIC_KEY_FROM_PRIVATE_KEY = False 10 | PRIVATE_KEY_FILE = "nelsonkey.pem" 11 | PUBLIC_KEY_FILE = "nelsonkey.pub" 12 | MESSAGE = b"Nelson likes cat" 13 | 14 | if GENERATE_PRIVATE_KEY: 15 | # Generate private key 16 | private_key = rsa.generate_private_key( 17 | public_exponent=65537, 18 | key_size=2048, 19 | backend=default_backend() 20 | ) 21 | else: 22 | # Load private key from pem file 23 | with open(PRIVATE_KEY_FILE, "rb") as key_file: 24 | private_key = serialization.load_pem_private_key( 25 | key_file.read(), 26 | password=None, 27 | backend=default_backend() 28 | ) 29 | 30 | signature = private_key.sign( 31 | MESSAGE, 32 | padding.PSS( 33 | mgf=padding.MGF1(hashes.SHA256()), 34 | salt_length=padding.PSS.MAX_LENGTH 35 | ), 36 | hashes.SHA256() 37 | ) 38 | 39 | 40 | if DERIVE_PUBLIC_KEY_FROM_PRIVATE_KEY: 41 | # Getting public key from private key 42 | public_key = private_key.public_key() 43 | else: 44 | # Load public key from file 45 | with open(PUBLIC_KEY_FILE, "rb") as key_file: 46 | public_key = serialization.load_pem_public_key( 47 | key_file.read(), 48 | backend=default_backend() 49 | ) 50 | 51 | public_key.verify( 52 | signature, 53 | MESSAGE, 54 | padding.PSS( 55 | mgf=padding.MGF1(hashes.SHA256()), 56 | salt_length=padding.PSS.MAX_LENGTH 57 | ), 58 | hashes.SHA256() 59 | ) 60 | 61 | print(signature) 62 | -------------------------------------------------------------------------------- /Chapter02/my_first_smart_contract/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Chapter02/my_first_smart_contract/contracts/donation.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Donation { 4 | address public donatur; 5 | address payable donatee; 6 | uint public money; 7 | string public useless_variable; 8 | 9 | constructor() public { 10 | donatee = msg.sender; 11 | useless_variable = "Donation string"; 12 | } 13 | 14 | function change_useless_variable(string memory param) public { 15 | useless_variable = param; 16 | } 17 | 18 | function donate() public payable { 19 | donatur = msg.sender; 20 | money = msg.value; 21 | } 22 | 23 | function receive_donation() public { 24 | donatee.transfer(address(this).balance); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Chapter02/my_first_smart_contract/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /Chapter02/my_first_smart_contract/migrations/2_deploy_donation.js: -------------------------------------------------------------------------------- 1 | var Donation = artifacts.require("./Donation.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Donation); 5 | }; 6 | -------------------------------------------------------------------------------- /Chapter02/my_first_smart_contract/truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | "development": { 4 | network_id: 5777, 5 | host: "localhost", 6 | port: 7545 7 | }, 8 | }, 9 | mocha: { 10 | }, 11 | compilers: { 12 | solc: { 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /Chapter03/compiler.py: -------------------------------------------------------------------------------- 1 | import vyper 2 | import os, json 3 | 4 | filename = 'hello.vy' 5 | contract_name = 'Hello' 6 | contract_json_file = open('Hello.json', 'w') 7 | 8 | with open(filename, 'r') as f: 9 | content = f.read() 10 | 11 | current_directory = 'haha' # os.curdir 12 | 13 | smart_contract = {} 14 | smart_contract[current_directory] = content 15 | 16 | format = ['abi', 'bytecode'] 17 | compiled_code = vyper.compile_codes(smart_contract, format, 'dict') 18 | 19 | smart_contract_json = { 20 | 'contractName': contract_name, 21 | 'abi': compiled_code[current_directory]['abi'], 22 | 'bytecode': compiled_code[current_directory]['bytecode'] 23 | } 24 | 25 | json.dump(smart_contract_json, contract_json_file) 26 | 27 | contract_json_file.close() 28 | -------------------------------------------------------------------------------- /Chapter03/donation.vy: -------------------------------------------------------------------------------- 1 | struct DonaturDetail: 2 | sum: uint256(wei) 3 | name: bytes[100] 4 | time: timestamp 5 | 6 | donatur_details: public(map(address, DonaturDetail)) 7 | 8 | donaturs: public(address[10]) 9 | 10 | donatee: public(address) 11 | 12 | index: int128 13 | 14 | @public 15 | def __init__(): 16 | self.donatee = msg.sender 17 | 18 | @payable 19 | @public 20 | def donate(name: bytes[100]): 21 | assert msg.value >= as_wei_value(1, "ether") 22 | assert self.index < 10 23 | 24 | self.donatur_details[msg.sender] = DonaturDetail({ 25 | sum: msg.value, 26 | name: name, 27 | time: block.timestamp 28 | }) 29 | 30 | self.donaturs[self.index] = msg.sender 31 | self.index += 1 32 | 33 | @public 34 | def withdraw_donation(): 35 | assert msg.sender == self.donatee 36 | 37 | send(self.donatee, self.balance) 38 | -------------------------------------------------------------------------------- /Chapter03/donation_call_hello_contract.vy: -------------------------------------------------------------------------------- 1 | struct DonaturDetail: 2 | sum: uint256(wei) 3 | name: bytes[100] 4 | time: timestamp 5 | 6 | contract Hello(): 7 | def say_hello() -> bytes[32]: constant 8 | 9 | donatur_details: public(map(address, DonaturDetail)) 10 | 11 | infinite_array_of_strings: map(uint256, bytes[100]) 12 | 13 | mapping_of_mapping_of_mapping: map(uint256, map(uint256, map(uint256, bytes[10]))) 14 | 15 | donaturs: public(address[10]) 16 | 17 | donatee: public(address) 18 | 19 | index: int128 20 | 21 | @public 22 | def __init__(): 23 | self.donatee = msg.sender 24 | 25 | @payable 26 | @public 27 | def donate(name: bytes[100]): 28 | assert msg.value >= as_wei_value(1, "ether") 29 | assert self.index < 10 30 | 31 | self.donatur_details[msg.sender] = DonaturDetail({ 32 | sum: msg.value, 33 | name: name, 34 | time: block.timestamp 35 | }) 36 | 37 | self.donaturs[self.index] = msg.sender 38 | self.index += 1 39 | 40 | @public 41 | def withdraw_donation(): 42 | assert msg.sender == self.donatee 43 | 44 | send(self.donatee, self.balance) 45 | 46 | @public 47 | @constant 48 | def donation_smart_contract_call_hello_smart_contract_method(smart_contract_address: address) -> bytes[32]: 49 | return Hello(smart_contract_address).say_hello() 50 | -------------------------------------------------------------------------------- /Chapter03/hello.vy: -------------------------------------------------------------------------------- 1 | name: public(bytes[24]) 2 | 3 | @public 4 | def __init__(): 5 | self.name = "Satoshi Nakamoto" 6 | 7 | @public 8 | def change_name(new_name: bytes[24]): 9 | self.name = new_name 10 | 11 | @public 12 | def say_hello() -> bytes[32]: 13 | return concat("Hello, ", self.name) 14 | -------------------------------------------------------------------------------- /Chapter04/deploy_smart_contract_to_ganache.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | from vyper import compile_codes 3 | 4 | 5 | contract_source_code = ''' 6 | name: public(bytes[24]) 7 | 8 | @public 9 | def __init__(): 10 | self.name = "Satoshi Nakamoto" 11 | 12 | @public 13 | def change_name(new_name: bytes[24]): 14 | self.name = new_name 15 | 16 | @public 17 | def say_hello() -> bytes[32]: 18 | return concat("Hello, ", self.name) 19 | ''' 20 | 21 | smart_contract = {} 22 | smart_contract['hello'] = contract_source_code 23 | 24 | format = ['abi', 'bytecode'] 25 | compiled_code = compile_codes(smart_contract, format, 'dict') 26 | 27 | bytecode = compiled_code['hello']['bytecode'] 28 | abi = compiled_code['hello']['abi'] 29 | 30 | w3 = Web3(HTTPProvider('http://localhost:7545')) 31 | 32 | HelloSmartContract = w3.eth.contract(abi=abi, bytecode=bytecode) 33 | 34 | # Change the account to your situation. 35 | tx_hash = HelloSmartContract.constructor().transact({'from': '0xb105F01Ce341Ef9282dc2201BDfdA2c26903da77'}) 36 | 37 | tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) 38 | print(tx_receipt) 39 | -------------------------------------------------------------------------------- /Chapter04/deploy_smart_contract_to_rinkeby.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | from vyper import compile_codes 3 | 4 | 5 | contract_source_code = ''' 6 | name: public(bytes[24]) 7 | 8 | @public 9 | def __init__(): 10 | self.name = "Satoshi Nakamoto" 11 | 12 | @public 13 | def change_name(new_name: bytes[24]): 14 | self.name = new_name 15 | 16 | @public 17 | def say_hello() -> bytes[32]: 18 | return concat("Hello, ", self.name) 19 | ''' 20 | 21 | smart_contract = {} 22 | smart_contract['hello'] = contract_source_code 23 | 24 | format = ['abi', 'bytecode'] 25 | compiled_code = compile_codes(smart_contract, format, 'dict') 26 | 27 | bytecode = compiled_code['hello']['bytecode'] 28 | abi = compiled_code['hello']['abi'] 29 | 30 | # Change the path of geth.ipc according to your situation. 31 | w3 = Web3(IPCProvider('/opt/data/ethereumdata/geth.ipc')) 32 | 33 | HelloSmartContract = w3.eth.contract(abi=abi, bytecode=bytecode) 34 | 35 | # Change the account, the password, and the path to the keystore according to your situation, 36 | from_account = "0x28f5b56b035da966afa609f65fd8f7d71ff68327" 37 | password = 'password123' 38 | with open('/opt/data/ethereumdata/keystore/UTC--2018-10-12T09-30-20.687898000Z--28f5b56b035da966afa609f65fd8f7d71ff68327') as keyfile: 39 | encrypted_key = keyfile.read() 40 | private_key = w3.eth.account.decrypt(encrypted_key, password) 41 | 42 | nonce = w3.eth.getTransactionCount(Web3.toChecksumAddress(from_account)) 43 | 44 | transaction = HelloSmartContract.constructor().buildTransaction({'from': Web3.toChecksumAddress(from_account), 45 | 'gas': 500000, 46 | 'gasPrice': w3.toWei('30', 'gwei'), 47 | 'nonce': nonce}) 48 | 49 | signed = w3.eth.account.signTransaction(transaction, private_key) 50 | tx_hash = w3.eth.sendRawTransaction(signed.rawTransaction) 51 | 52 | tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) 53 | print(tx_receipt) 54 | -------------------------------------------------------------------------------- /Chapter04/estimate_gas.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | 3 | 4 | w3 = Web3(HTTPProvider('http://localhost:7545')) 5 | 6 | transaction = { 7 | 'to': Web3.toChecksumAddress('0x9049386D4d5808e0Cd9e294F2aA3d70F01Fbf0C5'), 8 | 'value': w3.toWei('1', 'ether'), 9 | 'gas': 100000, 10 | 'gasPrice': w3.toWei('1', 'gwei'), 11 | 'nonce': 0 12 | } 13 | 14 | print("Estimating gas usage: " + str(w3.eth.estimateGas(transaction))) 15 | print("Gas price: " + str(w3.eth.gasPrice)) 16 | -------------------------------------------------------------------------------- /Chapter04/extract_private_key.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3 2 | w3 = Web3() 3 | 4 | # Change the filepath to your keystore's filepath 5 | with open('/opt/data/ethereumdata/keystore/UTC--2018-10-12T09-30-20.687898000Z--28f5b56b035da966afa609f65fd8f7d71ff68327') as keyfile: 6 | encrypted_key = keyfile.read() 7 | private_key = w3.eth.account.decrypt(encrypted_key, 'password123') 8 | print(private_key) 9 | -------------------------------------------------------------------------------- /Chapter04/get_latest_nonce.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | 3 | 4 | web3 = Web3(HTTPProvider('http://localhost:7545')) 5 | 6 | nonce = web3.eth.getTransactionCount("0x6d3eBC3000d112B70aaCA8F770B06f961C852014") 7 | print(nonce) 8 | -------------------------------------------------------------------------------- /Chapter04/play_with_smart_contract_in_ganache.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | from vyper import compile_codes 3 | 4 | 5 | contract_source_code = ''' 6 | name: public(bytes[24]) 7 | 8 | @public 9 | def __init__(): 10 | self.name = "Satoshi Nakamoto" 11 | 12 | @public 13 | def change_name(new_name: bytes[24]): 14 | self.name = new_name 15 | 16 | @public 17 | def say_hello() -> bytes[32]: 18 | return concat("Hello, ", self.name) 19 | ''' 20 | 21 | smart_contract = {} 22 | smart_contract['hello'] = contract_source_code 23 | 24 | format = ['abi', 'bytecode'] 25 | compiled_code = compile_codes(smart_contract, format, 'dict') 26 | 27 | abi = compiled_code['hello']['abi'] 28 | 29 | w3 = Web3(HTTPProvider('http://localhost:7545')) 30 | 31 | # Change the address of the smart contract, the private key, and the account according to your situation 32 | address = "0x9Dc44aa8d05c86388E647F954D00CaA858837804" 33 | private_key = '0x1a369cedacf0bf2f5fd16b5215527e8c8767cbd761ebefa28d9df0d389c60b6e' 34 | w3.eth.defaultAccount = '0xb105F01Ce341Ef9282dc2201BDfdA2c26903da77' 35 | 36 | Hello = w3.eth.contract(address=address, abi=abi) 37 | 38 | print(Hello.functions.name().call()) 39 | 40 | print(Hello.functions.say_hello().call()) 41 | 42 | nonce = w3.eth.getTransactionCount(w3.eth.defaultAccount) 43 | 44 | txn = Hello.functions.change_name(b"Lionel Messi").buildTransaction({ 45 | 'gas': 70000, 46 | 'gasPrice': w3.toWei('1', 'gwei'), 47 | 'nonce': nonce 48 | }) 49 | 50 | signed_txn = w3.eth.account.signTransaction(txn, private_key=private_key) 51 | 52 | signed_txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction) 53 | 54 | w3.eth.waitForTransactionReceipt(signed_txn_hash) 55 | 56 | print(Hello.functions.say_hello().call()) 57 | -------------------------------------------------------------------------------- /Chapter04/play_with_smart_contract_in_rinkeby.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | from vyper import compile_codes 3 | 4 | 5 | contract_source_code = ''' 6 | name: public(bytes[24]) 7 | 8 | @public 9 | def __init__(): 10 | self.name = "Satoshi Nakamoto" 11 | 12 | @public 13 | def change_name(new_name: bytes[24]): 14 | self.name = new_name 15 | 16 | @public 17 | def say_hello() -> bytes[32]: 18 | return concat("Hello, ", self.name) 19 | ''' 20 | 21 | smart_contract = {} 22 | smart_contract['hello'] = contract_source_code 23 | 24 | format = ['abi', 'bytecode'] 25 | compiled_code = compile_codes(smart_contract, format, 'dict') 26 | 27 | abi = compiled_code['hello']['abi'] 28 | 29 | # Change the path of geth.ipc according to your situation. 30 | w3 = Web3(IPCProvider('/opt/data/ethereumdata/geth.ipc')) 31 | 32 | from web3.middleware import geth_poa_middleware 33 | w3.middleware_stack.inject(geth_poa_middleware, layer=0) 34 | 35 | # Change the address of the smart contract, the account, the password, and the path to the keystore according to your situation, 36 | address = "0x58705EBBc791DB917c7771FdA6175b2D9F59D51A" 37 | password = 'password123' 38 | w3.eth.defaultAccount = '0x28f5b56b035da966afa609f65fd8f7d71ff68327' 39 | with open('/opt/data/ethereumdata/keystore/UTC--2018-10-12T09-30-20.687898000Z--28f5b56b035da966afa609f65fd8f7d71ff68327') as keyfile: 40 | encrypted_key = keyfile.read() 41 | private_key = w3.eth.account.decrypt(encrypted_key, password) 42 | 43 | Hello = w3.eth.contract(address=address, abi=abi) 44 | 45 | print(Hello.functions.name().call()) 46 | 47 | print(Hello.functions.say_hello().call()) 48 | 49 | nonce = w3.eth.getTransactionCount(w3.eth.defaultAccount) 50 | 51 | txn = Hello.functions.change_name(b"Lionel Messi").buildTransaction({ 52 | 'gas': 500000, 53 | 'gasPrice': w3.toWei('30', 'gwei'), 54 | 'nonce': nonce 55 | }) 56 | 57 | signed_txn = w3.eth.account.signTransaction(txn, private_key=private_key) 58 | 59 | signed_txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction) 60 | 61 | w3.eth.waitForTransactionReceipt(signed_txn_hash) 62 | 63 | print(Hello.functions.say_hello().call()) 64 | -------------------------------------------------------------------------------- /Chapter04/send_money_ganache.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | 3 | 4 | w3 = Web3(HTTPProvider('http://localhost:7545')) 5 | 6 | private_key = '59e31694256f71b8d181f47fc67914798c4b96990e835fc1407bf4673ead30e2' 7 | 8 | transaction = { 9 | 'to': Web3.toChecksumAddress('0x9049386D4d5808e0Cd9e294F2aA3d70F01Fbf0C5'), 10 | 'value': w3.toWei('1', 'ether'), 11 | 'gas': 100000, 12 | 'gasPrice': w3.toWei('1', 'gwei'), 13 | 'nonce': 0 14 | } 15 | 16 | signed = w3.eth.account.signTransaction(transaction, private_key) 17 | tx = w3.eth.sendRawTransaction(signed.rawTransaction) 18 | -------------------------------------------------------------------------------- /Chapter04/send_money_rinkeby.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | from web3.middleware import geth_poa_middleware 3 | 4 | # Change the path of geth.ipc according to your situation. 5 | w3 = Web3(IPCProvider('/opt/data/ethereumdata/geth.ipc')) 6 | 7 | w3.middleware_stack.inject(geth_poa_middleware, layer=0) 8 | 9 | # Change the destination account, the sender account, the password, and the path to the keystore according to your situation, 10 | password = 'password123' 11 | from_account = "0x28f5b56b035da966afa609f65fd8f7d71ff68327" 12 | to_account = '0x99fb2eee85acbf878d4154de73d5fb1b7e88c328' 13 | with open('/opt/data/ethereumdata/keystore/UTC--2018-10-12T09-30-20.687898000Z--28f5b56b035da966afa609f65fd8f7d71ff68327') as keyfile: 14 | encrypted_key = keyfile.read() 15 | private_key = w3.eth.account.decrypt(encrypted_key, password) 16 | 17 | nonce = w3.eth.getTransactionCount(Web3.toChecksumAddress(from_account)) 18 | 19 | transaction = { 20 | 'to': Web3.toChecksumAddress(to_account), 21 | 'value': w3.toWei('1', 'ether'), 22 | 'gas': 21000, 23 | 'gasPrice': w3.toWei('2', 'gwei'), 24 | 'nonce': nonce 25 | } 26 | 27 | signed = w3.eth.account.signTransaction(transaction, private_key) 28 | w3.eth.sendRawTransaction(signed.rawTransaction) 29 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/contracts/Donation.vy: -------------------------------------------------------------------------------- 1 | struct DonaturDetail: 2 | sum: uint256(wei) 3 | name: bytes[100] 4 | time: timestamp 5 | 6 | donatur_details: public(map(address, DonaturDetail)) 7 | 8 | donaturs: public(address[10]) 9 | 10 | donatee: public(address) 11 | 12 | index: int128 13 | 14 | @public 15 | def __init__(): 16 | self.donatee = msg.sender 17 | 18 | @payable 19 | @public 20 | def donate(name: bytes[100]): 21 | assert msg.value >= as_wei_value(1, "ether") 22 | assert self.index < 10 23 | 24 | self.donatur_details[msg.sender] = DonaturDetail({ 25 | sum: msg.value, 26 | name: name, 27 | time: block.timestamp 28 | }) 29 | 30 | self.donaturs[self.index] = msg.sender 31 | self.index += 1 32 | 33 | @public 34 | def withdraw_donation(): 35 | assert msg.sender == self.donatee 36 | 37 | send(self.donatee, self.balance) 38 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/contracts/Greeter.vy: -------------------------------------------------------------------------------- 1 | greeting: bytes[20] 2 | 3 | 4 | @public 5 | def __init__(): 6 | self.greeting = "Hello" 7 | 8 | 9 | @public 10 | def setGreeting(x: bytes[20]): 11 | self.greeting = x 12 | 13 | 14 | @public 15 | def greet() -> bytes[20]: 16 | return self.greeting 17 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/contracts/Greeter2.vy: -------------------------------------------------------------------------------- 1 | greeting: bytes[20] 2 | 3 | 4 | @public 5 | def __init__(greeting_param: bytes[20]): 6 | self.greeting = greeting_param 7 | 8 | 9 | @public 10 | def setGreeting(x: bytes[20]): 11 | self.greeting = x 12 | 13 | 14 | @public 15 | def greet() -> bytes[20]: 16 | return self.greeting 17 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/interact_smart_contract_in_ganache.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | w3 = Web3(HTTPProvider("http://localhost:7545")) 3 | 4 | print(w3.eth.coinbase) 5 | print(w3.eth.getBalance(w3.eth.coinbase)) 6 | 7 | # Change this address to your smart contract address 8 | address = "0x9Dc44aa8d05c86388E647F954D00CaA858837804" 9 | false = False 10 | true = True 11 | abi = [ 12 | { 13 | "constant": false, 14 | "inputs": [], 15 | "name": "__init__", 16 | "outputs": [], 17 | "payable": false, 18 | "type": "constructor" 19 | }, 20 | { 21 | "constant": false, 22 | "gas": 317989, 23 | "inputs": [ 24 | { 25 | "name": "name", 26 | "type": "bytes" 27 | } 28 | ], 29 | "name": "donate", 30 | "outputs": [], 31 | "payable": true, 32 | "type": "function" 33 | }, 34 | { 35 | "constant": false, 36 | "gas": 35996, 37 | "inputs": [], 38 | "name": "withdraw_donation", 39 | "outputs": [], 40 | "payable": false, 41 | "type": "function" 42 | }, 43 | { 44 | "constant": true, 45 | "gas": 793, 46 | "inputs": [ 47 | { 48 | "name": "arg0", 49 | "type": "address" 50 | } 51 | ], 52 | "name": "donatur_details__sum", 53 | "outputs": [ 54 | { 55 | "name": "out", 56 | "type": "uint256" 57 | } 58 | ], 59 | "payable": false, 60 | "type": "function" 61 | }, 62 | { 63 | "constant": true, 64 | "gas": 18462, 65 | "inputs": [ 66 | { 67 | "name": "arg0", 68 | "type": "address" 69 | } 70 | ], 71 | "name": "donatur_details__name", 72 | "outputs": [ 73 | { 74 | "name": "out", 75 | "type": "bytes" 76 | } 77 | ], 78 | "payable": false, 79 | "type": "function" 80 | }, 81 | { 82 | "constant": true, 83 | "gas": 853, 84 | "inputs": [ 85 | { 86 | "name": "arg0", 87 | "type": "address" 88 | } 89 | ], 90 | "name": "donatur_details__time", 91 | "outputs": [ 92 | { 93 | "name": "out", 94 | "type": "uint256" 95 | } 96 | ], 97 | "payable": false, 98 | "type": "function" 99 | }, 100 | { 101 | "constant": true, 102 | "gas": 850, 103 | "inputs": [ 104 | { 105 | "name": "arg0", 106 | "type": "int128" 107 | } 108 | ], 109 | "name": "donaturs", 110 | "outputs": [ 111 | { 112 | "name": "out", 113 | "type": "address" 114 | } 115 | ], 116 | "payable": false, 117 | "type": "function" 118 | }, 119 | { 120 | "constant": true, 121 | "gas": 663, 122 | "inputs": [], 123 | "name": "donatee", 124 | "outputs": [ 125 | { 126 | "name": "out", 127 | "type": "address" 128 | } 129 | ], 130 | "payable": false, 131 | "type": "function" 132 | } 133 | ] 134 | 135 | donation = w3.eth.contract(address=address, abi=abi) 136 | print(donation.functions.donatee().call()) 137 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/interact_smart_contract_in_private_chain.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | w3 = Web3(IPCProvider(ipc_path="/tmp/geth.ipc")) 3 | 4 | print(w3.eth.coinbase) 5 | print(w3.eth.getBalance(w3.eth.coinbase)) 6 | 7 | # Change this address to your smart contract address 8 | address = "0xab3B30CFeC1D50DCb0a13671D09d55e63b7cFf40" 9 | false = False 10 | true = True 11 | abi = [ 12 | { 13 | "constant": false, 14 | "inputs": [], 15 | "name": "__init__", 16 | "outputs": [], 17 | "payable": false, 18 | "type": "constructor" 19 | }, 20 | { 21 | "constant": false, 22 | "gas": 317989, 23 | "inputs": [ 24 | { 25 | "name": "name", 26 | "type": "bytes" 27 | } 28 | ], 29 | "name": "donate", 30 | "outputs": [], 31 | "payable": true, 32 | "type": "function" 33 | }, 34 | { 35 | "constant": false, 36 | "gas": 35996, 37 | "inputs": [], 38 | "name": "withdraw_donation", 39 | "outputs": [], 40 | "payable": false, 41 | "type": "function" 42 | }, 43 | { 44 | "constant": true, 45 | "gas": 793, 46 | "inputs": [ 47 | { 48 | "name": "arg0", 49 | "type": "address" 50 | } 51 | ], 52 | "name": "donatur_details__sum", 53 | "outputs": [ 54 | { 55 | "name": "out", 56 | "type": "uint256" 57 | } 58 | ], 59 | "payable": false, 60 | "type": "function" 61 | }, 62 | { 63 | "constant": true, 64 | "gas": 18462, 65 | "inputs": [ 66 | { 67 | "name": "arg0", 68 | "type": "address" 69 | } 70 | ], 71 | "name": "donatur_details__name", 72 | "outputs": [ 73 | { 74 | "name": "out", 75 | "type": "bytes" 76 | } 77 | ], 78 | "payable": false, 79 | "type": "function" 80 | }, 81 | { 82 | "constant": true, 83 | "gas": 853, 84 | "inputs": [ 85 | { 86 | "name": "arg0", 87 | "type": "address" 88 | } 89 | ], 90 | "name": "donatur_details__time", 91 | "outputs": [ 92 | { 93 | "name": "out", 94 | "type": "uint256" 95 | } 96 | ], 97 | "payable": false, 98 | "type": "function" 99 | }, 100 | { 101 | "constant": true, 102 | "gas": 850, 103 | "inputs": [ 104 | { 105 | "name": "arg0", 106 | "type": "int128" 107 | } 108 | ], 109 | "name": "donaturs", 110 | "outputs": [ 111 | { 112 | "name": "out", 113 | "type": "address" 114 | } 115 | ], 116 | "payable": false, 117 | "type": "function" 118 | }, 119 | { 120 | "constant": true, 121 | "gas": 663, 122 | "inputs": [], 123 | "name": "donatee", 124 | "outputs": [ 125 | { 126 | "name": "out", 127 | "type": "address" 128 | } 129 | ], 130 | "payable": false, 131 | "type": "function" 132 | } 133 | ] 134 | 135 | donation = w3.eth.contract(address=address, abi=abi) 136 | print(donation.functions.donatee().call()) 137 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/tests/__pycache__/test_donation.cpython-36-PYTEST.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter05/populus_tutorial/tests/__pycache__/test_donation.cpython-36-PYTEST.pyc -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/tests/__pycache__/test_greeter.cpython-36-PYTEST.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter05/populus_tutorial/tests/__pycache__/test_greeter.cpython-36-PYTEST.pyc -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/tests/__pycache__/test_greeter2.cpython-36-PYTEST.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter05/populus_tutorial/tests/__pycache__/test_greeter2.cpython-36-PYTEST.pyc -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/tests/test_donation.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import eth_tester 3 | 4 | 5 | def test_donatee(web3, chain): 6 | donation, _ = chain.provider.get_or_deploy_contract('Donation') 7 | 8 | donatee = donation.functions.donatee().call() 9 | assert donatee == web3.eth.coinbase 10 | 11 | def test_donate_less_than_1_eth(web3, chain): 12 | donation, _ = chain.provider.get_or_deploy_contract('Donation') 13 | 14 | with pytest.raises(eth_tester.exceptions.TransactionFailed): 15 | donation.functions.donate(b'Taylor Swift').transact({'value': web3.toWei('0.8', 'ether')}) 16 | 17 | def test_donate_1_eth(web3, chain): 18 | import time 19 | 20 | donation, _ = chain.provider.get_or_deploy_contract('Donation') 21 | 22 | t = eth_tester.EthereumTester() 23 | account2 = t.get_accounts()[1] 24 | 25 | donatur_name = b'Taylor Swift' 26 | set_txn_hash = donation.functions.donate(donatur_name).transact({'from': account2, 'value': web3.toWei('1', 'ether')}) 27 | chain.wait.for_receipt(set_txn_hash) 28 | 29 | donatur = donation.functions.donaturs(0).call() 30 | donation_sum = donation.functions.donatur_details__sum(donatur).call() 31 | donation_name = donation.functions.donatur_details__name(donatur).call() 32 | donation_time = donation.functions.donatur_details__time(donatur).call() 33 | 34 | assert donatur == account2 35 | assert donation_sum == web3.toWei('1', 'ether') 36 | assert donation_name == donatur_name 37 | assert (int(time.time()) - donation_time) < 600 # could be flaky 38 | 39 | assert web3.eth.getBalance(donation.address) == web3.toWei('1', 'ether') 40 | 41 | def test_other_account_could_not_withdraw_money(web3, chain): 42 | donation, _ = chain.provider.get_or_deploy_contract('Donation') 43 | 44 | t = eth_tester.EthereumTester() 45 | account2 = t.get_accounts()[1] 46 | 47 | donatur_name = b'Taylor Swift' 48 | set_txn_hash = donation.functions.donate(donatur_name).transact({'from': account2, 'value': web3.toWei('1', 'ether')}) 49 | chain.wait.for_receipt(set_txn_hash) 50 | 51 | with pytest.raises(eth_tester.exceptions.TransactionFailed): 52 | donation.functions.withdraw_donation().transact({'from': account2}) 53 | 54 | def test_manager_account_could_withdraw_money(web3, chain): 55 | donation, _ = chain.provider.get_or_deploy_contract('Donation') 56 | 57 | t = eth_tester.EthereumTester() 58 | account2 = t.get_accounts()[1] 59 | 60 | donatur_name = b'Taylor Swift' 61 | set_txn_hash = donation.functions.donate(donatur_name).transact({'from': account2, 'value': web3.toWei('1', 'ether')}) 62 | chain.wait.for_receipt(set_txn_hash) 63 | 64 | initial_balance = web3.eth.getBalance(web3.eth.coinbase) 65 | set_txn_hash = donation.functions.withdraw_donation().transact({'from': web3.eth.coinbase}) 66 | chain.wait.for_receipt(set_txn_hash) 67 | 68 | after_withdraw_balance = web3.eth.getBalance(web3.eth.coinbase) 69 | 70 | assert abs((after_withdraw_balance - initial_balance) - web3.toWei('1', 'ether')) < web3.toWei('10', 'gwei') 71 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/tests/test_greeter.py: -------------------------------------------------------------------------------- 1 | def test_greeter(chain): 2 | greeter, _ = chain.provider.get_or_deploy_contract('Greeter') 3 | 4 | greeting = greeter.functions.greet().call() 5 | assert greeting == b'Hello' 6 | 7 | 8 | def test_custom_greeting(chain): 9 | greeter, _ = chain.provider.get_or_deploy_contract('Greeter') 10 | 11 | set_txn_hash = greeter.functions.setGreeting(b'Guten Tag').transact() 12 | chain.wait.for_receipt(set_txn_hash) 13 | 14 | greeting = greeter.functions.greet().call() 15 | assert greeting == b'Guten Tag' 16 | -------------------------------------------------------------------------------- /Chapter05/populus_tutorial/tests/test_greeter2.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | @pytest.fixture() 4 | def greeter2_contract(chain): 5 | Greeter2Factory = chain.provider.get_contract_factory('Greeter2') 6 | deploy_txn_hash = Greeter2Factory.constructor(b'Hola').transact() 7 | contract_address = chain.wait.for_contract_address(deploy_txn_hash) 8 | return Greeter2Factory(address=contract_address) 9 | 10 | def test_greeter2(greeter2_contract): 11 | greeting2 = greeter2_contract.functions.greet().call() 12 | assert greeting2 == b'Hola' 13 | -------------------------------------------------------------------------------- /Chapter06/voting_dapp/address.txt: -------------------------------------------------------------------------------- 1 | 0x993FFADB39D323D8B134F6f0CdD83d510c45D306 2 | -------------------------------------------------------------------------------- /Chapter06/voting_dapp/client_address.txt: -------------------------------------------------------------------------------- 1 | 86B84a2cCCFfef5c8B2c30E6366674A6C1613BFb 2 | -------------------------------------------------------------------------------- /Chapter06/voting_dapp/get_bytecode_from_smart_contract_address.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | 3 | w3 = Web3(IPCProvider(ipc_path='/tmp/geth.ipc')) 4 | 5 | with open('address.txt', 'r') as f: 6 | content = f.read().rstrip("\n") 7 | 8 | address = content 9 | 10 | 11 | -------------------------------------------------------------------------------- /Chapter06/voting_dapp/simple_voting_client.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | from populus.utils.wait import wait_for_transaction_receipt 3 | import glob 4 | 5 | w3 = Web3(IPCProvider(ipc_path='/tmp/geth.ipc')) 6 | 7 | with open('client_address.txt', 'r') as f: 8 | content = f.read().rstrip("\n") 9 | 10 | address = content.lower() 11 | 12 | encrypted_private_key_file = glob.glob('../voting_project/chains/localblock/chain_data/keystore/*' + address)[0] 13 | with open(encrypted_private_key_file) as f: 14 | password = 'password123' 15 | private_key = w3.eth.account.decrypt(f.read(), password) 16 | w3.eth.defaultAccount = '0x' + address 17 | 18 | 19 | false = False 20 | true = True 21 | abi = [ 22 | { 23 | "anonymous": false, 24 | "inputs": [ 25 | { 26 | "indexed": true, 27 | "name": "_from", 28 | "type": "address" 29 | }, 30 | { 31 | "indexed": false, 32 | "name": "_proposal", 33 | "type": "int128" 34 | } 35 | ], 36 | "name": "Voting", 37 | "type": "event" 38 | }, 39 | { 40 | "constant": false, 41 | "inputs": [ 42 | { 43 | "name": "_proposalNames", 44 | "type": "bytes32[2]" 45 | } 46 | ], 47 | "name": "__init__", 48 | "outputs": [], 49 | "payable": false, 50 | "type": "constructor" 51 | }, 52 | { 53 | "constant": false, 54 | "gas": 73421, 55 | "inputs": [ 56 | { 57 | "name": "proposal", 58 | "type": "int128" 59 | } 60 | ], 61 | "name": "vote", 62 | "outputs": [], 63 | "payable": false, 64 | "type": "function" 65 | }, 66 | { 67 | "constant": true, 68 | "gas": 4006, 69 | "inputs": [], 70 | "name": "winner_name", 71 | "outputs": [ 72 | { 73 | "name": "out", 74 | "type": "bytes32" 75 | } 76 | ], 77 | "payable": false, 78 | "type": "function" 79 | }, 80 | { 81 | "constant": true, 82 | "gas": 868, 83 | "inputs": [ 84 | { 85 | "name": "arg0", 86 | "type": "int128" 87 | } 88 | ], 89 | "name": "proposals__name", 90 | "outputs": [ 91 | { 92 | "name": "out", 93 | "type": "bytes32" 94 | } 95 | ], 96 | "payable": false, 97 | "type": "function" 98 | }, 99 | { 100 | "constant": true, 101 | "gas": 904, 102 | "inputs": [ 103 | { 104 | "name": "arg0", 105 | "type": "int128" 106 | } 107 | ], 108 | "name": "proposals__vote_count", 109 | "outputs": [ 110 | { 111 | "name": "out", 112 | "type": "int128" 113 | } 114 | ], 115 | "payable": false, 116 | "type": "function" 117 | }, 118 | { 119 | "constant": true, 120 | "gas": 633, 121 | "inputs": [], 122 | "name": "proposals_count", 123 | "outputs": [ 124 | { 125 | "name": "out", 126 | "type": "int128" 127 | } 128 | ], 129 | "payable": false, 130 | "type": "function" 131 | }, 132 | { 133 | "constant": true, 134 | "gas": 835, 135 | "inputs": [ 136 | { 137 | "name": "arg0", 138 | "type": "address" 139 | } 140 | ], 141 | "name": "voters_voted", 142 | "outputs": [ 143 | { 144 | "name": "out", 145 | "type": "int128" 146 | } 147 | ], 148 | "payable": false, 149 | "type": "function" 150 | } 151 | ] 152 | 153 | with open('address.txt', 'r') as f: 154 | content = f.read().rstrip("\n") 155 | 156 | smart_contract_address = content 157 | 158 | SimpleVoting = w3.eth.contract(address=smart_contract_address, abi=abi) 159 | 160 | nonce = w3.eth.getTransactionCount(Web3.toChecksumAddress(w3.eth.defaultAccount)) 161 | 162 | txn = SimpleVoting.functions.vote(0).buildTransaction({ 163 | 'gas': 70000, 164 | 'gasPrice': w3.toWei('1', 'gwei'), 165 | 'nonce': nonce 166 | }) 167 | 168 | signed = w3.eth.account.signTransaction(txn, private_key=private_key) 169 | w3.eth.sendRawTransaction(signed.rawTransaction) 170 | -------------------------------------------------------------------------------- /Chapter06/voting_dapp/watch_simple_voting.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | 3 | w3 = Web3(IPCProvider(ipc_path='/tmp/geth.ipc')) 4 | 5 | false = False 6 | true = True 7 | abi = [ 8 | { 9 | "anonymous": false, 10 | "inputs": [ 11 | { 12 | "indexed": true, 13 | "name": "_from", 14 | "type": "address" 15 | }, 16 | { 17 | "indexed": false, 18 | "name": "_proposal", 19 | "type": "int128" 20 | } 21 | ], 22 | "name": "Voting", 23 | "type": "event" 24 | }, 25 | { 26 | "constant": false, 27 | "inputs": [ 28 | { 29 | "name": "_proposalNames", 30 | "type": "bytes32[2]" 31 | } 32 | ], 33 | "name": "__init__", 34 | "outputs": [], 35 | "payable": false, 36 | "type": "constructor" 37 | }, 38 | { 39 | "constant": false, 40 | "gas": 73421, 41 | "inputs": [ 42 | { 43 | "name": "proposal", 44 | "type": "int128" 45 | } 46 | ], 47 | "name": "vote", 48 | "outputs": [], 49 | "payable": false, 50 | "type": "function" 51 | }, 52 | { 53 | "constant": true, 54 | "gas": 4006, 55 | "inputs": [], 56 | "name": "winner_name", 57 | "outputs": [ 58 | { 59 | "name": "out", 60 | "type": "bytes32" 61 | } 62 | ], 63 | "payable": false, 64 | "type": "function" 65 | }, 66 | { 67 | "constant": true, 68 | "gas": 868, 69 | "inputs": [ 70 | { 71 | "name": "arg0", 72 | "type": "int128" 73 | } 74 | ], 75 | "name": "proposals__name", 76 | "outputs": [ 77 | { 78 | "name": "out", 79 | "type": "bytes32" 80 | } 81 | ], 82 | "payable": false, 83 | "type": "function" 84 | }, 85 | { 86 | "constant": true, 87 | "gas": 904, 88 | "inputs": [ 89 | { 90 | "name": "arg0", 91 | "type": "int128" 92 | } 93 | ], 94 | "name": "proposals__vote_count", 95 | "outputs": [ 96 | { 97 | "name": "out", 98 | "type": "int128" 99 | } 100 | ], 101 | "payable": false, 102 | "type": "function" 103 | }, 104 | { 105 | "constant": true, 106 | "gas": 633, 107 | "inputs": [], 108 | "name": "proposals_count", 109 | "outputs": [ 110 | { 111 | "name": "out", 112 | "type": "int128" 113 | } 114 | ], 115 | "payable": false, 116 | "type": "function" 117 | }, 118 | { 119 | "constant": true, 120 | "gas": 835, 121 | "inputs": [ 122 | { 123 | "name": "arg0", 124 | "type": "address" 125 | } 126 | ], 127 | "name": "voters_voted", 128 | "outputs": [ 129 | { 130 | "name": "out", 131 | "type": "int128" 132 | } 133 | ], 134 | "payable": false, 135 | "type": "function" 136 | } 137 | ] 138 | 139 | with open('address.txt', 'r') as f: 140 | content = f.read().rstrip("\n") 141 | 142 | address = content 143 | 144 | SimpleVoting = w3.eth.contract(address=address, abi=abi) 145 | 146 | event_filter = SimpleVoting.events.Voting.createFilter(fromBlock=1) 147 | 148 | import time 149 | while True: 150 | print(event_filter.get_new_entries()) 151 | time.sleep(2) 152 | -------------------------------------------------------------------------------- /Chapter06/voting_project/10_accounts.txt: -------------------------------------------------------------------------------- 1 | 0x139D95864176F56401439C449c12f2d4b36712F6 2 | 0x36461a003a03f857D60f5bD0B8e8a64aAB4e4535 3 | 0xDED72BA25f492bE5AB1cE806128D4Cc0F2033d10 4 | 0x2DD74d520Fe64180be7dBB25edBb5f44de0b59aA 5 | 0x2327AE719A2edc554F7Aef0153D5bc45a0385146 6 | 0xd52F4502fCC1AAAD26c6D7BAfF0b79B9692c523F 7 | 0xB98463474Ddc78ea54050dFAbc6F55964Fd01DA2 8 | 0x093bbE836281B6eCb0777dc3405f893CeDB30Ef2 9 | 0xf0738EF5635f947f13dD41F34DAe6B2caa0a9EA6 10 | 0x86B84a2cCCFfef5c8B2c30E6366674A6C1613BFb 11 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/000018.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/000018.log -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/000020.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/000020.ldb -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000019 2 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/CURRENT.bak: -------------------------------------------------------------------------------- 1 | MANIFEST-000015 2 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/LOG: -------------------------------------------------------------------------------- 1 | =============== Oct 26, 2018 (WIB) =============== 2 | 11:48:20.287058 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed 3 | 11:48:20.306720 db@open opening 4 | 11:48:20.307440 version@stat F·[] S·0B[] Sc·[] 5 | 11:48:20.311804 db@janitor F·2 G·0 6 | 11:48:20.311824 db@open done T·5.089308ms 7 | =============== Oct 26, 2018 (WIB) =============== 8 | 11:49:02.553588 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed 9 | 11:49:02.553669 version@stat F·[] S·0B[] Sc·[] 10 | 11:49:02.553674 db@open opening 11 | 11:49:02.553694 journal@recovery F·1 12 | 11:49:02.555412 journal@recovery recovering @1 13 | 11:49:02.565866 memdb@flush created L0@2 N·11 S·731B "H\xb5\b..\xab\xaa,,v5":"sec..M\xdd(,v1" 14 | 11:49:02.567636 version@stat F·[1] S·731B[731B] Sc·[0.25] 15 | 11:49:02.586294 db@janitor F·3 G·0 16 | 11:49:02.586387 db@open done T·32.665273ms 17 | 13:53:07.088257 db@close closing 18 | 13:53:07.088291 db@close done T·33.33µs 19 | =============== Oct 26, 2018 (WIB) =============== 20 | 20:03:43.106112 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed 21 | 20:03:43.106455 version@stat F·[1] S·731B[731B] Sc·[0.25] 22 | 20:03:43.106504 db@open opening 23 | 20:03:43.106532 journal@recovery F·1 24 | 20:03:43.108429 journal@recovery recovering @3 25 | 20:03:43.163144 memdb@flush created L0@5 N·24059 S·1MiB "\x0f6g..$\x88\xc9,v24065":"\xeck\xfe..\xe7a],v24058" 26 | 20:03:43.171252 version@stat F·[2] S·1MiB[1MiB] Sc·[0.50] 27 | 20:03:43.188234 db@janitor F·4 G·0 28 | 20:03:43.188319 db@open done T·81.796148ms 29 | 20:05:18.855138 table@compaction L0·2 -> L1·0 S·1MiB Q·24236 30 | 20:05:18.873398 table@build created L1@8 N·16056 S·906KiB "\x0f6g..$\x88\xc9,v24065":"\xeck\xfe..\xe7a],v24058" 31 | 20:05:18.873439 version@stat F·[0 1] S·906KiB[0B 906KiB] Sc·[0.00 0.01] 32 | 20:05:18.877846 table@compaction committed F-1 S-326KiB Ke·0 D·8014 T·22.683932ms 33 | 20:05:18.877998 table@remove removed @5 34 | 20:05:18.878026 table@remove removed @2 35 | 20:43:54.884573 db@close closing 36 | 20:43:54.884651 db@close done T·77.894µs 37 | =============== Oct 27, 2018 (WIB) =============== 38 | 11:56:01.291389 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed 39 | 11:56:01.292154 version@stat F·[0 1] S·906KiB[0B 906KiB] Sc·[0.00 0.01] 40 | 11:56:01.292202 db@open opening 41 | 11:56:01.292356 journal@recovery F·1 42 | 11:56:01.311475 journal@recovery recovering @6 43 | 11:56:01.328042 memdb@flush created L0@9 N·4066 S·216KiB "\x02\xe1\xfb..Z\x98c,v28126":"\xfe\rk..\x90\x99\xbc,v28122" 44 | 11:56:01.329709 version@stat F·[1 1] S·1MiB[216KiB 906KiB] Sc·[0.25 0.01] 45 | 11:56:01.344880 db@janitor F·4 G·0 46 | 11:56:01.344944 db@open done T·52.721075ms 47 | 11:59:51.021745 table@compaction L0·1 -> L1·1 S·1MiB Q·28541 48 | 11:59:51.046420 table@build created L1@12 N·18783 S·1MiB "\x02\xe1\xfb..Z\x98c,v28126":"\xfe\rk..\x90\x99\xbc,v28122" 49 | 11:59:51.046453 version@stat F·[0 1] S·1MiB[0B 1MiB] Sc·[0.00 0.01] 50 | 11:59:51.050251 table@compaction committed F-1 S-55KiB Ke·0 D·1339 T·28.480342ms 51 | 11:59:51.050312 table@remove removed @9 52 | 11:59:51.050384 table@remove removed @8 53 | 14:24:40.662602 db@close closing 54 | 14:24:40.662692 db@close done T·87.907µs 55 | =============== Oct 27, 2018 (WIB) =============== 56 | 15:30:59.475369 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed 57 | 15:30:59.475471 version@stat F·[0 1] S·1MiB[0B 1MiB] Sc·[0.00 0.01] 58 | 15:30:59.475477 db@open opening 59 | 15:30:59.475502 journal@recovery F·1 60 | 15:30:59.477125 journal@recovery recovering @10 61 | 15:30:59.504038 memdb@flush created L0@13 N·13822 S·633KiB "\x0e&r..!\xac\x15,v41958":"\xe9\b\xc7..bTW,v41956" 62 | 15:30:59.511229 version@stat F·[1 1] S·1MiB[633KiB 1MiB] Sc·[0.25 0.01] 63 | 15:30:59.527157 db@janitor F·4 G·0 64 | 15:30:59.527231 db@open done T·51.737007ms 65 | 15:31:46.525245 table@compaction L0·1 -> L1·1 S·1MiB Q·42029 66 | 15:31:46.560132 table@build created L1@16 N·28681 S·1MiB "\x02\xe1\xfb..Z\x98c,v28126":"\xfe\rk..\x90\x99\xbc,v28122" 67 | 15:31:46.560177 version@stat F·[0 1] S·1MiB[0B 1MiB] Sc·[0.00 0.02] 68 | 15:31:46.566003 table@compaction committed F-1 S-160KiB Ke·0 D·3924 T·40.723055ms 69 | 15:31:46.566138 table@remove removed @13 70 | 15:31:46.566292 table@remove removed @12 71 | 17:41:08.645866 db@close closing 72 | 17:41:08.645901 db@close done T·34.519µs 73 | =============== Oct 29, 2018 (WIB) =============== 74 | 10:28:09.147552 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed 75 | 10:28:09.148330 version@stat F·[0 1] S·1MiB[0B 1MiB] Sc·[0.00 0.02] 76 | 10:28:09.148371 db@open opening 77 | 10:28:09.148580 journal@recovery F·1 78 | 10:28:09.177398 journal@recovery recovering @14 79 | 10:28:09.226443 memdb@flush created L0@17 N·8085 S·417KiB "\vm=..\xe1\xf5\x10,v50041":"\xf7ڪ..M\x17\xc1,v50030" 80 | 10:28:09.229265 version@stat F·[1 1] S·1MiB[417KiB 1MiB] Sc·[0.25 0.02] 81 | 10:28:09.243206 db@janitor F·4 G·0 82 | 10:28:09.243232 db@open done T·94.841332ms 83 | 10:33:29.722386 table@compaction L0·1 -> L1·1 S·1MiB Q·50447 84 | 10:33:29.754540 table@build created L1@20 N·34073 S·1MiB "\x02\xe1\xfb..Z\x98c,v28126":"\xfe\rk..\x90\x99\xbc,v28122" 85 | 10:33:29.754575 version@stat F·[0 1] S·1MiB[0B 1MiB] Sc·[0.00 0.02] 86 | 10:33:29.758481 table@compaction committed F-1 S-110KiB Ke·0 D·2693 T·36.06689ms 87 | 10:33:29.758555 table@remove removed @17 88 | 10:33:29.758658 table@remove removed @16 89 | 14:34:08.617509 db@close closing 90 | 14:34:08.617544 db@close done T·34.076µs 91 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/MANIFEST-000019: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter06/voting_project/chains/localblock/chain_data/geth/chaindata/MANIFEST-000019 -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/lightchaindata/000001.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter06/voting_project/chains/localblock/chain_data/geth/lightchaindata/000001.log -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/lightchaindata/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000000 2 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/lightchaindata/LOG: -------------------------------------------------------------------------------- 1 | =============== Oct 26, 2018 (WIB) =============== 2 | 11:48:20.312326 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed 3 | 11:48:20.320592 db@open opening 4 | 11:48:20.321784 version@stat F·[] S·0B[] Sc·[] 5 | 11:48:20.326414 db@janitor F·2 G·0 6 | 11:48:20.326458 db@open done T·5.835614ms 7 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/lightchaindata/MANIFEST-000000: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter06/voting_project/chains/localblock/chain_data/geth/lightchaindata/MANIFEST-000000 -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/nodekey: -------------------------------------------------------------------------------- 1 | 6b65f7d4bd98293f043182ad032cef6499827d6c69c6c71dc29a4c3e91549935 -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/chain_data/geth/transactions.rlp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter06/voting_project/chains/localblock/chain_data/geth/transactions.rlp -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/genesis.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 4 | "coinbase": "0xfa146d7af4b92eb1751c3c9c644fa436a60f7b75", 5 | "extraData": "0x686f727365", 6 | "config": { 7 | "daoForkBlock": 0, 8 | "daoForSupport": true, 9 | "homesteadBlock": 0 10 | }, 11 | "timestamp": "0x0", 12 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 13 | "nonce": "0xdeadbeefdeadbeef", 14 | "alloc": { 15 | "0xfa146d7af4b92eb1751c3c9c644fa436a60f7b75":{ 16 | "balance": "1000000000000000000000000000000" 17 | } 18 | }, 19 | "gasLimit": "0x47d5cc", 20 | "difficulty": "0x01" 21 | } 22 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/init_chain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpcapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --ws --wsaddr 127.0.0.1 --wsport 8546 --wsapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --datadir /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_06/voting_project/chains/localblock/chain_data --maxpeers 0 --networkid 1234 --port 30303 --ipcpath /tmp/tmpvnbzbt29/geth.ipc --nodiscover --mine --minerthreads 1 init /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_06/voting_project/chains/localblock/genesis.json -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/password: -------------------------------------------------------------------------------- 1 | this-is-not-a-secure-password 2 | -------------------------------------------------------------------------------- /Chapter06/voting_project/chains/localblock/run_chain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpcapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --ws --wsaddr 127.0.0.1 --wsport 8546 --wsapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --datadir /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_06/voting_project/chains/localblock/chain_data --maxpeers 0 --networkid 1234 --port 30303 --ipcpath /tmp/tmpvnbzbt29/geth.ipc --unlock 0xfa146d7af4b92eb1751c3c9c644fa436a60f7b75 --password /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_06/voting_project/chains/localblock/password --nodiscover --mine --minerthreads 1 --ipcpath /tmp/geth.ipc 3 | -------------------------------------------------------------------------------- /Chapter06/voting_project/create_10_accounts_on_private_chain.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | 3 | w3 = Web3(IPCProvider(ipc_path='/tmp/geth.ipc')) 4 | 5 | with open('10_accounts.txt', 'w') as f: 6 | for i in range(10): 7 | f.write(w3.personal.newAccount('password123') + "\n") 8 | -------------------------------------------------------------------------------- /Chapter06/voting_project/deploy_SmartVoting.py: -------------------------------------------------------------------------------- 1 | from populus import Project 2 | from populus.utils.wait import wait_for_transaction_receipt 3 | 4 | 5 | def main(): 6 | 7 | project = Project() 8 | 9 | chain_name = "ganache" 10 | 11 | with project.get_chain(chain_name) as chain: 12 | 13 | SimpleVoting = chain.provider.get_contract_factory('SimpleVoting') 14 | 15 | txhash = SimpleVoting.deploy(transaction={"from": chain.web3.eth.coinbase}, args=[[b'Messi', b'Ronaldo']]) 16 | receipt = wait_for_transaction_receipt(chain.web3, txhash) 17 | simple_voting_address = receipt["contractAddress"] 18 | print("SimpleVoting contract address is", simple_voting_address) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | 24 | -------------------------------------------------------------------------------- /Chapter06/voting_project/distribute_money.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | from populus.utils.wait import wait_for_transaction_receipt 3 | import glob 4 | 5 | w3 = Web3(IPCProvider(ipc_path='/tmp/geth.ipc')) 6 | 7 | address = 'fa146d7af4b92eb1751c3c9c644fa436a60f7b75' 8 | 9 | with open('chains/localblock/password') as f: 10 | password = f.read().rstrip("\n") 11 | 12 | encrypted_private_key_file = glob.glob('chains/localblock/chain_data/keystore/*' + address)[0] 13 | with open(encrypted_private_key_file) as f2: 14 | private_key = w3.eth.account.decrypt(f2.read(), password) 15 | 16 | w3.eth.defaultAccount = w3.eth.coinbase 17 | 18 | with open('10_accounts.txt', 'r') as f: 19 | accounts = f.readlines() 20 | for account in accounts: 21 | nonce = w3.eth.getTransactionCount(Web3.toChecksumAddress(w3.eth.defaultAccount)) 22 | transaction = { 23 | 'to': Web3.toChecksumAddress(account.rstrip("\n")), 24 | 'value': w3.toWei('10', 'ether'), 25 | 'gas': 1000000, 26 | 'gasPrice': w3.toWei('20', 'gwei'), 27 | 'nonce': nonce 28 | } 29 | 30 | signed = w3.eth.account.signTransaction(transaction, private_key) 31 | txhash = w3.eth.sendRawTransaction(signed.rawTransaction) 32 | wait_for_transaction_receipt(w3, txhash) 33 | 34 | -------------------------------------------------------------------------------- /Chapter06/voting_project/get_bytecode_from_address.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | 3 | w3 = Web3(HTTPProvider('http://127.0.0.1:8545')) 4 | print(w3.eth.getCode('0x891dfe5Dbf551E090805CEee41b94bB2205Bdd17')) 5 | -------------------------------------------------------------------------------- /Chapter06/voting_project/how_much_money_do_i_have.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, IPCProvider 2 | 3 | w3 = Web3(IPCProvider(ipc_path='/tmp/geth.ipc')) 4 | 5 | print(w3.fromWei(w3.eth.getBalance(w3.eth.coinbase), 'ether')) 6 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import QApplication, QWidget 3 | 4 | app = QApplication(sys.argv) 5 | 6 | window = QWidget() 7 | window.resize(400, 400) 8 | 9 | window.show() 10 | sys.exit(app.exec_()) 11 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_connect_param.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QLabel 3 | from PySide2 import QtCore 4 | 5 | app = QApplication(sys.argv) 6 | 7 | hello_line_edit = QLineEdit() 8 | world_label = QLabel("") 9 | 10 | layout = QVBoxLayout() 11 | layout.addWidget(hello_line_edit) 12 | layout.addWidget(world_label) 13 | 14 | def set_world_label(text): 15 | world_label.setText(text.upper()) 16 | 17 | hello_line_edit.textChanged.connect(set_world_label) 18 | #hello_line_edit.connect(QtCore.SIGNAL('textChanged(QString)'), set_world_label) 19 | 20 | window = QWidget() 21 | window.setLayout(layout) 22 | window.resize(200, 200) 23 | 24 | window.show() 25 | sys.exit(app.exec_()) 26 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_connect_signal_slot.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QLabel 3 | from PySide2 import QtCore 4 | 5 | app = QApplication(sys.argv) 6 | 7 | hello_line_edit = QLineEdit() 8 | world_label = QLabel("") 9 | 10 | layout = QVBoxLayout() 11 | layout.addWidget(hello_line_edit) 12 | layout.addWidget(world_label) 13 | 14 | hello_line_edit.connect(QtCore.SIGNAL('textChanged(QString)'), world_label, QtCore.SLOT('setText(QString)')) 15 | #QtCore.QObject.connect(hello_line_edit, QtCore.SIGNAL('textChanged(QString)'), world_label, QtCore.SLOT('setText(QString)')) 16 | 17 | window = QWidget() 18 | window.setLayout(layout) 19 | window.resize(200, 200) 20 | 21 | window.show() 22 | sys.exit(app.exec_()) 23 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_connect_simple.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLabel 3 | from PySide2 import QtCore 4 | 5 | app = QApplication(sys.argv) 6 | 7 | hello_button = QPushButton("Hello") 8 | world_label = QLabel("Sun") 9 | 10 | layout = QVBoxLayout() 11 | layout.addWidget(hello_button) 12 | layout.addWidget(world_label) 13 | 14 | def set_text_in_world_label(): 15 | world_label.setText("World") 16 | 17 | hello_button.connect(QtCore.SIGNAL('clicked()'), set_text_in_world_label) 18 | 19 | window = QWidget() 20 | window.setLayout(layout) 21 | window.resize(200, 200) 22 | 23 | window.show() 24 | sys.exit(app.exec_()) 25 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_custom_signal_slot.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2 import QtCore 3 | 4 | @QtCore.Slot(str) 5 | def slot_func(param): 6 | print(param) 7 | 8 | class Simple(QtCore.QObject): 9 | signal = QtCore.Signal(str) 10 | 11 | simple = Simple() 12 | simple.signal.connect(slot_func) 13 | 14 | simple.signal.emit("Hello World") 15 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_horizontal_layout.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QLabel 3 | 4 | app = QApplication(sys.argv) 5 | 6 | hello_button = QPushButton('Hello') 7 | very_label = QLabel('Very Very') 8 | beautiful_button = QPushButton('Beautiful') 9 | world_label = QLabel('World') 10 | 11 | layout = QHBoxLayout() 12 | layout.addWidget(hello_button) 13 | layout.addWidget(very_label) 14 | layout.addWidget(beautiful_button) 15 | layout.addWidget(world_label) 16 | 17 | window = QWidget() 18 | window.setLayout(layout) 19 | window.resize(200, 200) 20 | 21 | window.show() 22 | sys.exit(app.exec_()) 23 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_thread.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtCore 2 | import time 3 | 4 | class SimpleThread(QtCore.QThread): 5 | 6 | def __init__(self, parent=None): 7 | super(SimpleThread, self).__init__(parent) 8 | 9 | def run(self): 10 | time.sleep(2) # simulating latency in network 11 | print("world") 12 | 13 | 14 | simple_thread = SimpleThread() 15 | simple_thread.start() 16 | 17 | print("hello") 18 | simple_thread.wait() 19 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_varieties.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import (QApplication, 3 | QWidget, 4 | QVBoxLayout, 5 | QHBoxLayout, 6 | QGroupBox, 7 | QPushButton, 8 | QLabel, 9 | QSpinBox, 10 | QLineEdit, 11 | QRadioButton, 12 | QComboBox) 13 | 14 | app = QApplication(sys.argv) 15 | 16 | button = QPushButton('Button') 17 | label = QLabel('Label') 18 | spinbox = QSpinBox() 19 | lineedit = QLineEdit() 20 | radio_button1 = QRadioButton('Option 1') 21 | radio_button2 = QRadioButton('Option 2') 22 | radio_button3 = QRadioButton('Option 3') 23 | combo_box = QComboBox() 24 | combo_box.addItems(["Bitcoin", "Ethereum", "Monero", "Ripple"]) 25 | 26 | vlayout = QVBoxLayout() 27 | vlayout.addWidget(button) 28 | vlayout.addWidget(radio_button1) 29 | vlayout.addWidget(radio_button2) 30 | vlayout.addWidget(radio_button3) 31 | vlayout.addWidget(spinbox) 32 | 33 | hlayout = QHBoxLayout() 34 | hlayout.addWidget(lineedit) 35 | hlayout.addWidget(label) 36 | hlayout.addWidget(combo_box) 37 | 38 | top_groupbox = QGroupBox('Top') 39 | top_groupbox.setLayout(vlayout) 40 | 41 | bottom_groupbox = QGroupBox('Bottom') 42 | bottom_groupbox.setLayout(hlayout) 43 | 44 | layout = QVBoxLayout() 45 | layout.addWidget(top_groupbox) 46 | layout.addWidget(bottom_groupbox) 47 | 48 | window = QWidget() 49 | window.setLayout(layout) 50 | 51 | window.show() 52 | sys.exit(app.exec_()) 53 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_vertical_horizontal_layout.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel 3 | 4 | app = QApplication(sys.argv) 5 | 6 | hello_button = QPushButton('Hello') 7 | very_label = QLabel('Very Very') 8 | beautiful_button = QPushButton('Beautiful') 9 | world_label = QLabel('World') 10 | 11 | vertical_hello_button = QPushButton('Hello') 12 | vertical_very_label = QLabel('Very Very') 13 | vertical_beautiful_button = QPushButton('Beautiful') 14 | vertical_world_label = QLabel('World') 15 | 16 | vertical_layout = QVBoxLayout() 17 | vertical_layout.addWidget(vertical_hello_button) 18 | vertical_layout.addWidget(vertical_very_label) 19 | vertical_layout.addWidget(vertical_beautiful_button) 20 | vertical_layout.addWidget(vertical_world_label) 21 | 22 | horizontal_layout = QHBoxLayout() 23 | horizontal_layout.addWidget(hello_button) 24 | horizontal_layout.addWidget(very_label) 25 | horizontal_layout.addLayout(vertical_layout) 26 | horizontal_layout.addWidget(beautiful_button) 27 | horizontal_layout.addWidget(world_label) 28 | 29 | window = QWidget() 30 | window.setLayout(horizontal_layout) 31 | window.resize(200, 200) 32 | 33 | window.show() 34 | sys.exit(app.exec_()) 35 | -------------------------------------------------------------------------------- /Chapter07/crash_course_qt_for_python/hello_vertical_layout.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLabel 3 | 4 | app = QApplication(sys.argv) 5 | 6 | hello_button = QPushButton('Hello') 7 | very_label = QLabel('Very Very') 8 | beautiful_button = QPushButton('Beautiful') 9 | world_label = QLabel('World') 10 | 11 | layout = QVBoxLayout() 12 | layout.addWidget(hello_button) 13 | layout.addWidget(very_label) 14 | layout.addWidget(beautiful_button) 15 | layout.addWidget(world_label) 16 | 17 | window = QWidget() 18 | window.setLayout(layout) 19 | window.resize(200, 200) 20 | 21 | window.show() 22 | sys.exit(app.exec_()) 23 | -------------------------------------------------------------------------------- /Chapter07/dapp/address.txt: -------------------------------------------------------------------------------- 1 | 0x9Dc44aa8d05c86388E647F954D00CaA858837804 2 | -------------------------------------------------------------------------------- /Chapter07/dapp/fixtures.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3, HTTPProvider 2 | from populus.utils.wait import wait_for_transaction_receipt 3 | 4 | w3 = Web3(HTTPProvider('http://localhost:7545')) 5 | 6 | private_keys = ['dummy', 7 | '59e31694256f71b8d181f47fc67914798c4b96990e835fc1407bf4673ead30e2', 8 | 'ac1e6abbe002699fbef756a2cbc2bf8c03cfac97adee84ce32f198219be94788'] 9 | 10 | false = False 11 | true = True 12 | abi = [ 13 | { 14 | "constant": false, 15 | "gas": 71987, 16 | "inputs": [ 17 | { 18 | "name": "tweet", 19 | "type": "bytes32" 20 | } 21 | ], 22 | "name": "write_a_tweet", 23 | "outputs": [], 24 | "payable": false, 25 | "type": "function" 26 | }, 27 | { 28 | "constant": true, 29 | "gas": 968, 30 | "inputs": [ 31 | { 32 | "name": "arg0", 33 | "type": "address" 34 | }, 35 | { 36 | "name": "arg1", 37 | "type": "int128" 38 | } 39 | ], 40 | "name": "tweets__messages", 41 | "outputs": [ 42 | { 43 | "name": "out", 44 | "type": "bytes32" 45 | } 46 | ], 47 | "payable": false, 48 | "type": "function" 49 | }, 50 | { 51 | "constant": true, 52 | "gas": 787, 53 | "inputs": [ 54 | { 55 | "name": "arg0", 56 | "type": "address" 57 | } 58 | ], 59 | "name": "tweets__index", 60 | "outputs": [ 61 | { 62 | "name": "out", 63 | "type": "int128" 64 | } 65 | ], 66 | "payable": false, 67 | "type": "function" 68 | } 69 | ] 70 | 71 | with open('address.txt', 'r') as f: 72 | address = f.read().rstrip("\n") 73 | 74 | TwitterOnBlockchain = w3.eth.contract(address=address, abi=abi) 75 | 76 | for i in range(1, 3): 77 | for j in range(1, 11): 78 | nonce = w3.eth.getTransactionCount(Web3.toChecksumAddress(w3.eth.accounts[i])) 79 | txn = TwitterOnBlockchain.functions.write_a_tweet(b'Tweet ' + str(j).encode('utf-8')).buildTransaction({ 80 | 'gas': 70000, 81 | 'gasPrice': w3.toWei('1', 'gwei'), 82 | 'nonce': nonce 83 | }) 84 | 85 | signed = w3.eth.account.signTransaction(txn, private_key=private_keys[i]) 86 | txhash = w3.eth.sendRawTransaction(signed.rawTransaction) 87 | wait_for_transaction_receipt(w3, txhash) 88 | -------------------------------------------------------------------------------- /Chapter07/twitter_on_blockchain/build/contracts.json: -------------------------------------------------------------------------------- 1 | { 2 | "TwitterOnBlockchain": { 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "gas": 71987, 7 | "inputs": [ 8 | { 9 | "name": "tweet", 10 | "type": "bytes32" 11 | } 12 | ], 13 | "name": "write_a_tweet", 14 | "outputs": [], 15 | "payable": false, 16 | "type": "function" 17 | }, 18 | { 19 | "constant": true, 20 | "gas": 968, 21 | "inputs": [ 22 | { 23 | "name": "arg0", 24 | "type": "address" 25 | }, 26 | { 27 | "name": "arg1", 28 | "type": "int128" 29 | } 30 | ], 31 | "name": "tweets__messages", 32 | "outputs": [ 33 | { 34 | "name": "out", 35 | "type": "bytes32" 36 | } 37 | ], 38 | "payable": false, 39 | "type": "function" 40 | }, 41 | { 42 | "constant": true, 43 | "gas": 787, 44 | "inputs": [ 45 | { 46 | "name": "arg0", 47 | "type": "address" 48 | } 49 | ], 50 | "name": "tweets__index", 51 | "outputs": [ 52 | { 53 | "name": "out", 54 | "type": "int128" 55 | } 56 | ], 57 | "payable": false, 58 | "type": "function" 59 | } 60 | ], 61 | "bytecode": "0x61026556600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ac4cc57b600051141561016b57602060046101403734156100b457600080fd5b600a60003360e05260c052604060c02060c052602060c02054126100d757600080fd5b60003360e05260c052604060c02060c052602060c02054610160526101405161016051600a811061010757600080fd5b600160003360e05260c052604060c02060c052602060c0200160c052602060c020015560003360e05260c052604060c02060c052602060c02060605160018254018060405190131561015857600080fd5b809190121561016657600080fd5b815550005b632bd5f9176000511415610204576040600461014037341561018c57600080fd5b600435602051811061019d57600080fd5b50606051602435806040519013156101b457600080fd5b80919012156101c257600080fd5b5061016051600a81106101d457600080fd5b600160006101405160e05260c052604060c02060c052602060c0200160c052602060c020015460005260206000f3005b6372241d6e600051141561025b576020600461014037341561022557600080fd5b600435602051811061023657600080fd5b5060006101405160e05260c052604060c02060c052602060c0205460005260206000f3005b60006000fd5b61000461026503610004600039610004610265036000f3", 62 | "bytecode_runtime": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ac4cc57b600051141561016b57602060046101403734156100b457600080fd5b600a60003360e05260c052604060c02060c052602060c02054126100d757600080fd5b60003360e05260c052604060c02060c052602060c02054610160526101405161016051600a811061010757600080fd5b600160003360e05260c052604060c02060c052602060c0200160c052602060c020015560003360e05260c052604060c02060c052602060c02060605160018254018060405190131561015857600080fd5b809190121561016657600080fd5b815550005b632bd5f9176000511415610204576040600461014037341561018c57600080fd5b600435602051811061019d57600080fd5b50606051602435806040519013156101b457600080fd5b80919012156101c257600080fd5b5061016051600a81106101d457600080fd5b600160006101405160e05260c052604060c02060c052602060c0200160c052602060c020015460005260206000f3005b6372241d6e600051141561025b576020600461014037341561022557600080fd5b600435602051811061023657600080fd5b5060006101405160e05260c052604060c02060c052602060c0205460005260206000f3005b60006000fd", 63 | "direct_dependencies": [], 64 | "full_dependencies": [], 65 | "linkrefs": [], 66 | "linkrefs_runtime": [], 67 | "name": "TwitterOnBlockchain", 68 | "ordered_full_dependencies": [], 69 | "source_path": "contracts/TwitterOnBlockchain.vy" 70 | } 71 | } -------------------------------------------------------------------------------- /Chapter07/twitter_on_blockchain/contracts/TwitterOnBlockchain.vy: -------------------------------------------------------------------------------- 1 | struct Tweet: 2 | messages: bytes32[10] 3 | index: int128 4 | 5 | tweets: public(map(address, Tweet)) 6 | 7 | @public 8 | def write_a_tweet(tweet: bytes32): 9 | assert self.tweets[msg.sender].index < 10 10 | 11 | index: int128 = self.tweets[msg.sender].index 12 | self.tweets[msg.sender].messages[index] = tweet 13 | self.tweets[msg.sender].index += 1 14 | -------------------------------------------------------------------------------- /Chapter07/twitter_on_blockchain/tests/test_twitter_on_blockchain.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import eth_tester 3 | 4 | 5 | def test_initial_condition(web3, chain): 6 | twitter_on_blockchain, _ = chain.provider.get_or_deploy_contract('TwitterOnBlockchain') 7 | 8 | assert twitter_on_blockchain.functions.tweets__index(web3.eth.coinbase).call() == 0 9 | 10 | def test_write_a_tweet(web3, chain): 11 | twitter_on_blockchain, _ = chain.provider.get_or_deploy_contract('TwitterOnBlockchain') 12 | 13 | tweet = b'My first tweet ever!' 14 | set_txn_hash = twitter_on_blockchain.functions.write_a_tweet(tweet).transact() 15 | chain.wait.for_receipt(set_txn_hash) 16 | assert twitter_on_blockchain.functions.tweets__index(web3.eth.coinbase).call() == 1 17 | assert twitter_on_blockchain.functions.tweets__messages(web3.eth.coinbase,0).call()[:len(tweet)] == tweet 18 | 19 | tweet2 = b'I feel sad today.' 20 | set_txn_hash = twitter_on_blockchain.functions.write_a_tweet(tweet2).transact() 21 | chain.wait.for_receipt(set_txn_hash) 22 | assert twitter_on_blockchain.functions.tweets__index(web3.eth.coinbase).call() == 2 23 | assert twitter_on_blockchain.functions.tweets__messages(web3.eth.coinbase,0).call()[:len(tweet)] == tweet 24 | assert twitter_on_blockchain.functions.tweets__messages(web3.eth.coinbase,1).call()[:len(tweet2)] == tweet2 25 | -------------------------------------------------------------------------------- /Chapter08/token_project/chains/localblock/genesis.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 4 | "coinbase": "0x60d31d5e29a9c74448855b97017322972d4a798e", 5 | "extraData": "0x686f727365", 6 | "config": { 7 | "daoForkBlock": 0, 8 | "daoForSupport": true, 9 | "homesteadBlock": 0 10 | }, 11 | "timestamp": "0x0", 12 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 13 | "nonce": "0xdeadbeefdeadbeef", 14 | "alloc": { 15 | "0x60d31d5e29a9c74448855b97017322972d4a798e":{ 16 | "balance": "1000000000000000000000000000000" 17 | } 18 | }, 19 | "gasLimit": "0x47d5cc", 20 | "difficulty": "0x01" 21 | } 22 | -------------------------------------------------------------------------------- /Chapter08/token_project/chains/localblock/init_chain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpcapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --ws --wsaddr 127.0.0.1 --wsport 8546 --wsapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --datadir /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_08/token_project/chains/localblock/chain_data --maxpeers 0 --networkid 1234 --port 30303 --ipcpath /tmp/tmpjj4jkwss/geth.ipc --nodiscover --mine --minerthreads 1 init /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_08/token_project/chains/localblock/genesis.json -------------------------------------------------------------------------------- /Chapter08/token_project/chains/localblock/password: -------------------------------------------------------------------------------- 1 | this-is-not-a-secure-password 2 | -------------------------------------------------------------------------------- /Chapter08/token_project/chains/localblock/run_chain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpcapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --ws --wsaddr 127.0.0.1 --wsport 8546 --wsapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --datadir /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_08/token_project/chains/localblock/chain_data --maxpeers 0 --networkid 1234 --port 30303 --ipcpath /tmp/tmpjj4jkwss/geth.ipc --unlock 0x60d31d5e29a9c74448855b97017322972d4a798e --password /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_08/token_project/chains/localblock/password --nodiscover --mine --minerthreads 1 --ipcpath /tmp/geth.ipc 3 | -------------------------------------------------------------------------------- /Chapter08/token_project/contracts/CrowdSaleToken.vy: -------------------------------------------------------------------------------- 1 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) 2 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) 3 | Payment: event({_buyer: indexed(address), _value: uint256(wei)}) 4 | 5 | name: public(bytes[10]) 6 | symbol: public(bytes[3]) 7 | totalSupply: public(uint256) 8 | decimals: public(uint256) 9 | balances: map(address, uint256) 10 | ethBalances: public(map(address, uint256(wei))) 11 | allowed: map(address, map(address, uint256)) 12 | 13 | beneficiary: public(address) 14 | minFundingGoal: public(uint256(wei)) 15 | maxFundingGoal: public(uint256(wei)) 16 | amountRaised: public(uint256(wei)) 17 | deadline: public(timestamp) 18 | price: public(uint256(wei)) 19 | fundingGoalReached: public(bool) 20 | crowdsaleClosed: public(bool) 21 | 22 | @public 23 | def __init__(): 24 | _initialSupply: uint256 = 100 25 | _decimals: uint256 = 2 26 | self.totalSupply = _initialSupply * 10 ** _decimals 27 | self.name = 'Haha Coin' 28 | self.symbol = 'HAH' 29 | self.decimals = _decimals 30 | self.beneficiary = msg.sender 31 | self.balances[msg.sender] = self.totalSupply 32 | self.minFundingGoal = as_wei_value(30, "ether") 33 | self.maxFundingGoal = as_wei_value(50, "ether") 34 | self.amountRaised = 0 35 | self.deadline = block.timestamp + 3600 * 24 * 100 # 100 days 36 | self.price = as_wei_value(1, "ether") / 100 37 | self.fundingGoalReached = False 38 | self.crowdsaleClosed = False 39 | 40 | @public 41 | @payable 42 | def __default__(): 43 | assert msg.sender != self.beneficiary 44 | assert self.crowdsaleClosed == False 45 | assert self.amountRaised + msg.value < self.maxFundingGoal 46 | assert msg.value >= as_wei_value(0.01, "ether") 47 | self.ethBalances[msg.sender] += msg.value 48 | self.amountRaised += msg.value 49 | tokenAmount: uint256 = msg.value / self.price 50 | self.balances[msg.sender] += tokenAmount 51 | self.balances[self.beneficiary] -= tokenAmount 52 | log.Payment(msg.sender, msg.value) 53 | 54 | @public 55 | def checkGoalReached(): 56 | assert block.timestamp > self.deadline 57 | if self.amountRaised >= self.minFundingGoal: 58 | self.fundingGoalReached = True 59 | self.crowdsaleClosed = True 60 | 61 | @public 62 | def safeWithdrawal(): 63 | assert self.crowdsaleClosed == True 64 | if self.fundingGoalReached == False: 65 | if msg.sender != self.beneficiary: 66 | if self.ethBalances[msg.sender] > 0: 67 | self.ethBalances[msg.sender] = 0 68 | self.balances[self.beneficiary] += self.balances[msg.sender] 69 | self.balances[msg.sender] = 0 70 | send(msg.sender, self.ethBalances[msg.sender]) 71 | if self.fundingGoalReached == True: 72 | if msg.sender == self.beneficiary: 73 | if self.balance > 0: 74 | send(msg.sender, self.balance) 75 | 76 | @public 77 | @constant 78 | def balanceOf(_owner: address) -> uint256: 79 | return self.balances[_owner] 80 | 81 | @public 82 | def transfer(_to: address, _amount: uint256) -> bool: 83 | assert self.crowdsaleClosed == True 84 | assert self.balances[msg.sender] >= _amount 85 | self.balances[msg.sender] -= _amount 86 | self.balances[_to] += _amount 87 | log.Transfer(msg.sender, _to, _amount) 88 | 89 | return True 90 | 91 | @public 92 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool: 93 | assert self.crowdsaleClosed == True 94 | assert _value <= self.allowed[_from][msg.sender] 95 | assert _value <= self.balances[_from] 96 | 97 | self.balances[_from] -= _value 98 | self.allowed[_from][msg.sender] -= _value 99 | self.balances[_to] += _value 100 | log.Transfer(_from, _to, _value) 101 | 102 | return True 103 | 104 | @public 105 | def approve(_spender: address, _amount: uint256) -> bool: 106 | assert self.crowdsaleClosed == True 107 | self.allowed[msg.sender][_spender] = _amount 108 | log.Approval(msg.sender, _spender, _amount) 109 | 110 | return True 111 | 112 | @public 113 | @constant 114 | def allowance(_owner: address, _spender: address) -> uint256: 115 | return self.allowed[_owner][_spender] 116 | -------------------------------------------------------------------------------- /Chapter08/token_project/contracts/ERC20Token.vy: -------------------------------------------------------------------------------- 1 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) 2 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) 3 | 4 | name: public(bytes[10]) 5 | symbol: public(bytes[3]) 6 | totalSupply: public(uint256) 7 | decimals: public(uint256) 8 | balances: map(address, uint256) 9 | allowed: map(address, map(address, uint256)) 10 | 11 | @public 12 | def __init__(): 13 | _initialSupply: uint256 = 1000 14 | _decimals: uint256 = 3 15 | self.totalSupply = _initialSupply * 10 ** _decimals 16 | self.balances[msg.sender] = self.totalSupply 17 | self.name = 'Haha Coin' 18 | self.symbol = 'HAH' 19 | self.decimals = _decimals 20 | log.Transfer(ZERO_ADDRESS, msg.sender, self.totalSupply) 21 | 22 | @public 23 | @constant 24 | def balanceOf(_owner: address) -> uint256: 25 | return self.balances[_owner] 26 | 27 | @public 28 | def transfer(_to: address, _amount: uint256) -> bool: 29 | assert self.balances[msg.sender] >= _amount 30 | self.balances[msg.sender] -= _amount 31 | self.balances[_to] += _amount 32 | log.Transfer(msg.sender, _to, _amount) 33 | 34 | return True 35 | 36 | @public 37 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool: 38 | assert _value <= self.allowed[_from][msg.sender] 39 | assert _value <= self.balances[_from] 40 | 41 | self.balances[_from] -= _value 42 | self.allowed[_from][msg.sender] -= _value 43 | self.balances[_to] += _value 44 | log.Transfer(_from, _to, _value) 45 | 46 | return True 47 | 48 | @public 49 | def approve(_spender: address, _amount: uint256) -> bool: 50 | self.allowed[msg.sender][_spender] = _amount 51 | log.Approval(msg.sender, _spender, _amount) 52 | 53 | return True 54 | 55 | @public 56 | @constant 57 | def allowance(_owner: address, _spender: address) -> uint256: 58 | return self.allowed[_owner][_spender] 59 | -------------------------------------------------------------------------------- /Chapter08/token_project/contracts/SimpleToken.vy: -------------------------------------------------------------------------------- 1 | balances: public(map(address, uint256)) 2 | 3 | 4 | @public 5 | def __init__(): 6 | self.balances[msg.sender] = 10000 7 | 8 | 9 | @public 10 | def transfer(_to: address, _amount: uint256) -> bool: 11 | assert self.balances[msg.sender] >= _amount 12 | 13 | self.balances[msg.sender] -= _amount 14 | self.balances[_to] += _amount 15 | 16 | return True 17 | -------------------------------------------------------------------------------- /Chapter08/token_project/contracts/SimpleTokenMint.vy: -------------------------------------------------------------------------------- 1 | balances: public(map(address, uint256)) 2 | owner: address 3 | 4 | 5 | @public 6 | def __init__(): 7 | self.balances[msg.sender] = 10000 8 | self.owner = msg.sender 9 | 10 | 11 | @public 12 | def transfer(_to: address, _amount: uint256) -> bool: 13 | assert self.balances[msg.sender] >= _amount 14 | 15 | self.balances[msg.sender] -= _amount 16 | self.balances[_to] += _amount 17 | 18 | return True 19 | 20 | @public 21 | def mint(_new_supply: uint256): 22 | assert msg.sender == self.owner 23 | self.balances[msg.sender] = _new_supply 24 | -------------------------------------------------------------------------------- /Chapter08/token_project/contracts/StableCoin.vy: -------------------------------------------------------------------------------- 1 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) 2 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) 3 | Freeze: event({_account: indexed(address), _freeze: bool}) 4 | 5 | name: public(bytes[10]) 6 | symbol: public(bytes[3]) 7 | totalSupply: public(uint256) 8 | decimals: public(uint256) 9 | balances: map(address, uint256) 10 | allowed: map(address, map(address, uint256)) 11 | frozenBalances: public(map(address, bool)) 12 | owner: public(address) 13 | 14 | @public 15 | def __init__(): 16 | _initialSupply: uint256 = 1000 17 | _decimals: uint256 = 3 18 | self.totalSupply = _initialSupply * 10 ** _decimals 19 | self.balances[msg.sender] = self.totalSupply 20 | self.name = 'Haha Coin' 21 | self.symbol = 'HAH' 22 | self.decimals = _decimals 23 | self.owner = msg.sender 24 | log.Transfer(ZERO_ADDRESS, msg.sender, self.totalSupply) 25 | 26 | @public 27 | def freezeBalance(_target: address, _freeze: bool) -> bool: 28 | assert msg.sender == self.owner 29 | self.frozenBalances[_target] = _freeze 30 | log.Freeze(_target, _freeze) 31 | 32 | return True 33 | 34 | @public 35 | def mintToken(_mintedAmount: uint256) -> bool: 36 | assert msg.sender == self.owner 37 | self.totalSupply += _mintedAmount 38 | self.balances[msg.sender] += _mintedAmount 39 | log.Transfer(ZERO_ADDRESS, msg.sender, _mintedAmount) 40 | 41 | return True 42 | 43 | @public 44 | def burn(_burntAmount: uint256) -> bool: 45 | assert msg.sender == self.owner 46 | assert self.balances[msg.sender] >= _burntAmount 47 | self.totalSupply -= _burntAmount 48 | self.balances[msg.sender] -= _burntAmount 49 | log.Transfer(msg.sender, ZERO_ADDRESS, _burntAmount) 50 | 51 | return True 52 | 53 | @public 54 | @constant 55 | def balanceOf(_owner: address) -> uint256: 56 | return self.balances[_owner] 57 | 58 | @public 59 | def transfer(_to: address, _amount: uint256) -> bool: 60 | assert self.balances[msg.sender] >= _amount 61 | assert self.frozenBalances[msg.sender] == False 62 | self.balances[msg.sender] -= _amount 63 | self.balances[_to] += _amount 64 | log.Transfer(msg.sender, _to, _amount) 65 | 66 | return True 67 | 68 | @public 69 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool: 70 | assert _value <= self.allowed[_from][msg.sender] 71 | assert _value <= self.balances[_from] 72 | assert self.frozenBalances[msg.sender] == False 73 | 74 | self.balances[_from] -= _value 75 | self.allowed[_from][msg.sender] -= _value 76 | self.balances[_to] += _value 77 | log.Transfer(_from, _to, _value) 78 | 79 | return True 80 | 81 | @public 82 | def approve(_spender: address, _amount: uint256) -> bool: 83 | self.allowed[msg.sender][_spender] = _amount 84 | log.Approval(msg.sender, _spender, _amount) 85 | 86 | return True 87 | 88 | @public 89 | @constant 90 | def allowance(_owner: address, _spender: address) -> uint256: 91 | return self.allowed[_owner][_spender] 92 | -------------------------------------------------------------------------------- /Chapter08/token_project/tests/test_erc20_token.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import eth_tester 3 | 4 | 5 | def test_balance(web3, chain): 6 | erc20_token, _ = chain.provider.get_or_deploy_contract('ERC20Token') 7 | 8 | token_name = erc20_token.functions.name().call() 9 | token_symbol = erc20_token.functions.symbol().call() 10 | decimals = erc20_token.functions.decimals().call() 11 | total_supply = erc20_token.functions.totalSupply().call() 12 | balance = erc20_token.functions.balanceOf(web3.eth.coinbase).call() 13 | 14 | assert token_name == b"Haha Coin" 15 | assert token_symbol == b"HAH" 16 | assert decimals == 3 17 | assert total_supply == 1000000 18 | assert balance == 1000000 19 | 20 | def test_transfer(web3, chain): 21 | erc20_token, _ = chain.provider.get_or_deploy_contract('ERC20Token') 22 | 23 | t = eth_tester.EthereumTester() 24 | account2 = t.get_accounts()[1] 25 | 26 | old_balance = erc20_token.functions.balanceOf(account2).call() 27 | assert old_balance == 0 28 | 29 | set_txn_hash = erc20_token.functions.transfer(account2, 10).transact({'from': web3.eth.coinbase}) 30 | chain.wait.for_receipt(set_txn_hash) 31 | 32 | sender_new_balance = erc20_token.functions.balanceOf(web3.eth.coinbase).call() 33 | assert sender_new_balance == 999990 34 | destination_new_balance = erc20_token.functions.balanceOf(account2).call() 35 | assert destination_new_balance == 10 36 | 37 | def test_fail_transfer(web3, chain): 38 | erc20_token, _ = chain.provider.get_or_deploy_contract('ERC20Token') 39 | 40 | t = eth_tester.EthereumTester() 41 | account2 = t.get_accounts()[1] 42 | 43 | with pytest.raises(eth_tester.exceptions.TransactionFailed): 44 | erc20_token.functions.transfer(web3.eth.coinbase, 10).transact({'from': account2}) 45 | 46 | def test_approve(web3, chain): 47 | erc20_token, _ = chain.provider.get_or_deploy_contract('ERC20Token') 48 | 49 | t = eth_tester.EthereumTester() 50 | account2 = t.get_accounts()[1] 51 | 52 | allowance = erc20_token.functions.allowance(web3.eth.coinbase, account2).call() 53 | assert allowance == 0 54 | 55 | set_txn_hash = erc20_token.functions.approve(account2, 100).transact({'from': web3.eth.coinbase}) 56 | chain.wait.for_receipt(set_txn_hash) 57 | 58 | allowance = erc20_token.functions.allowance(web3.eth.coinbase, account2).call() 59 | assert allowance == 100 60 | 61 | def test_transferFrom(web3, chain): 62 | erc20_token, _ = chain.provider.get_or_deploy_contract('ERC20Token') 63 | 64 | t = eth_tester.EthereumTester() 65 | account2 = t.get_accounts()[1] 66 | account3 = t.get_accounts()[2] 67 | 68 | with pytest.raises(eth_tester.exceptions.TransactionFailed): 69 | erc20_token.functions.transferFrom(web3.eth.coinbase, account3, 10).transact({'from': account2}) 70 | 71 | set_txn_hash = erc20_token.functions.approve(account2, 100).transact({'from': web3.eth.coinbase}) 72 | chain.wait.for_receipt(set_txn_hash) 73 | 74 | set_txn_hash = erc20_token.functions.transferFrom(web3.eth.coinbase, account3, 10).transact({'from': account2}) 75 | chain.wait.for_receipt(set_txn_hash) 76 | 77 | balance_account1 = erc20_token.functions.balanceOf(web3.eth.coinbase).call() 78 | balance_account2 = erc20_token.functions.balanceOf(account2).call() 79 | balance_account3 = erc20_token.functions.balanceOf(account3).call() 80 | allowance = erc20_token.functions.allowance(web3.eth.coinbase, account2).call() 81 | 82 | assert balance_account1 == 999990 83 | assert balance_account2 == 0 84 | assert balance_account3 == 10 85 | assert allowance == 90 86 | -------------------------------------------------------------------------------- /Chapter08/token_project/tests/test_simple_token.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import eth_tester 3 | 4 | 5 | def test_balance(web3, chain): 6 | simple_token, _ = chain.provider.get_or_deploy_contract('SimpleToken') 7 | 8 | balance = simple_token.functions.balances(web3.eth.coinbase).call() 9 | assert balance == 10000 10 | 11 | def test_transfer(web3, chain): 12 | simple_token, _ = chain.provider.get_or_deploy_contract('SimpleToken') 13 | 14 | t = eth_tester.EthereumTester() 15 | account2 = t.get_accounts()[1] 16 | 17 | old_balance = simple_token.functions.balances(account2).call() 18 | assert old_balance == 0 19 | 20 | set_txn_hash = simple_token.functions.transfer(account2, 10).transact({'from': web3.eth.coinbase}) 21 | chain.wait.for_receipt(set_txn_hash) 22 | 23 | sender_new_balance = simple_token.functions.balances(web3.eth.coinbase).call() 24 | assert sender_new_balance == 9990 25 | destination_new_balance = simple_token.functions.balances(account2).call() 26 | assert destination_new_balance == 10 27 | 28 | def test_fail_transfer(web3, chain): 29 | simple_token, _ = chain.provider.get_or_deploy_contract('SimpleToken') 30 | 31 | t = eth_tester.EthereumTester() 32 | account2 = t.get_accounts()[1] 33 | 34 | with pytest.raises(eth_tester.exceptions.TransactionFailed): 35 | simple_token.functions.transfer(web3.eth.coinbase, 10).transact({'from': account2}) 36 | -------------------------------------------------------------------------------- /Chapter08/token_project/tests/test_stable_token.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import eth_tester 3 | import time 4 | 5 | def test_initialization(web3, chain): 6 | stable_coin, _ = chain.provider.get_or_deploy_contract('StableCoin') 7 | 8 | token_name = stable_coin.functions.name().call() 9 | token_symbol = stable_coin.functions.symbol().call() 10 | decimals = stable_coin.functions.decimals().call() 11 | total_supply = stable_coin.functions.totalSupply().call() 12 | owner = stable_coin.functions.owner().call() 13 | 14 | assert token_name == b"Haha Coin" 15 | assert token_symbol == b"HAH" 16 | assert decimals == 3 17 | assert total_supply == 1000000 18 | assert owner == web3.eth.coinbase 19 | 20 | def test_freeze_balance(web3, chain): 21 | stable_coin, _ = chain.provider.get_or_deploy_contract('StableCoin') 22 | 23 | t = eth_tester.EthereumTester() 24 | account2 = t.get_accounts()[1] 25 | account3 = t.get_accounts()[2] 26 | 27 | set_txn_hash = stable_coin.functions.transfer(account2, 10).transact() 28 | chain.wait.for_receipt(set_txn_hash) 29 | 30 | set_txn_hash = stable_coin.functions.transfer(account3, 1).transact({'from': account2}) 31 | chain.wait.for_receipt(set_txn_hash) 32 | 33 | set_txn_hash = stable_coin.functions.freezeBalance(account2, True).transact() 34 | chain.wait.for_receipt(set_txn_hash) 35 | 36 | with pytest.raises(eth_tester.exceptions.TransactionFailed): 37 | stable_coin.functions.transfer(account3, 1).transact({'from': account2}) 38 | 39 | set_txn_hash = stable_coin.functions.freezeBalance(account2, False).transact() 40 | chain.wait.for_receipt(set_txn_hash) 41 | 42 | set_txn_hash = stable_coin.functions.transfer(account3, 1).transact({'from': account2}) 43 | chain.wait.for_receipt(set_txn_hash) 44 | 45 | def test_mint_token(web3, chain): 46 | stable_coin, _ = chain.provider.get_or_deploy_contract('StableCoin') 47 | 48 | set_txn_hash = stable_coin.functions.mintToken(100).transact() 49 | chain.wait.for_receipt(set_txn_hash) 50 | 51 | new_total_supply = stable_coin.functions.totalSupply().call() 52 | assert new_total_supply == 1000100 53 | 54 | def test_burn_token(web3, chain): 55 | stable_coin, _ = chain.provider.get_or_deploy_contract('StableCoin') 56 | 57 | set_txn_hash = stable_coin.functions.burn(100).transact() 58 | chain.wait.for_receipt(set_txn_hash) 59 | 60 | new_total_supply = stable_coin.functions.totalSupply().call() 61 | assert new_total_supply == 999900 62 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/add_stretch.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QFrame, QLabel, QWidget, QApplication, QPushButton, QHBoxLayout, QVBoxLayout, QSizePolicy, QSizePolicy 2 | from PySide2.QtCore import Qt 3 | import sys 4 | 5 | 6 | class AddStretch(QWidget): 7 | 8 | def __init__(self): 9 | super(AddStretch, self).__init__() 10 | 11 | label1 = QLabel("label 1") 12 | label1.setFrameStyle(QFrame.Box) 13 | label2 = QLabel("label 2") 14 | label2.setFrameStyle(QFrame.Box) 15 | label3 = QLabel("label 3") 16 | label3.setFrameStyle(QFrame.Box) 17 | label4 = QLabel("label 4") 18 | label4.setFrameStyle(QFrame.Box) 19 | label5 = QLabel("label 5") 20 | label5.setFrameStyle(QFrame.Box) 21 | label6 = QLabel("label 6") 22 | label6.setFrameStyle(QFrame.Box) 23 | label7 = QLabel("label 7") 24 | label7.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) 25 | label7.setFrameStyle(QFrame.Box) 26 | label8 = QLabel("label 8") 27 | label8.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) 28 | label8.setFrameStyle(QFrame.Box) 29 | 30 | layout = QHBoxLayout() 31 | 32 | v_layout1 = QVBoxLayout() 33 | v_layout1.addWidget(label1) 34 | v_layout1.addWidget(label2) 35 | 36 | v_layout2 = QVBoxLayout() 37 | v_layout2.addWidget(label3) 38 | v_layout2.addWidget(label4) 39 | v_layout2.addStretch() 40 | 41 | v_layout3 = QVBoxLayout() 42 | v_layout3.addStretch() 43 | v_layout3.addWidget(label5) 44 | v_layout3.addWidget(label6) 45 | 46 | v_layout4 = QVBoxLayout() 47 | v_layout4.addWidget(label7) 48 | v_layout4.addWidget(label8) 49 | 50 | layout.addLayout(v_layout1) 51 | layout.addLayout(v_layout2) 52 | layout.addLayout(v_layout3) 53 | layout.addLayout(v_layout4) 54 | 55 | self.setLayout(layout) 56 | 57 | 58 | if __name__ == "__main__": 59 | 60 | app = QApplication(sys.argv) 61 | widget = AddStretch() 62 | widget.resize(500, 500) 63 | widget.show() 64 | sys.exit(app.exec_()) 65 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/button_and_dialog.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QWidget, QApplication, QLabel, QPushButton, QVBoxLayout, QInputDialog, QLineEdit 2 | from PySide2.QtCore import Qt 3 | import sys 4 | 5 | 6 | class ButtonAndDialog(QWidget): 7 | 8 | def __init__(self): 9 | super(ButtonAndDialog, self).__init__() 10 | 11 | self.button = QPushButton("button") 12 | self.button.clicked.connect(self.buttonClicked) 13 | 14 | self.label = QLabel("") 15 | 16 | layout = QVBoxLayout() 17 | layout.addWidget(self.button) 18 | layout.addWidget(self.label) 19 | 20 | self.setLayout(layout) 21 | 22 | def buttonClicked(self): 23 | new_text, ok = QInputDialog.getText(self, "Create A Text", 24 | "New Text:", QLineEdit.Normal) 25 | if ok and new_text != '': 26 | self.label.setText(new_text) 27 | 28 | 29 | if __name__ == "__main__": 30 | 31 | app = QApplication(sys.argv) 32 | button_and_dialog = ButtonAndDialog() 33 | button_and_dialog.show() 34 | sys.exit(app.exec_()) 35 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/button_and_label.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QWidget, QApplication, QLabel, QPushButton, QVBoxLayout 2 | from PySide2.QtCore import Qt 3 | import sys 4 | 5 | 6 | class ButtonAndLabel(QWidget): 7 | 8 | def __init__(self): 9 | super(ButtonAndLabel, self).__init__() 10 | 11 | self.button = QPushButton("button") 12 | self.button.clicked.connect(self.buttonClicked) 13 | 14 | self.label = QLabel("label: before clicked") 15 | 16 | layout = QVBoxLayout() 17 | layout.addWidget(self.button) 18 | layout.addWidget(self.label) 19 | 20 | self.setLayout(layout) 21 | 22 | def buttonClicked(self): 23 | self.label.setText("label: after clicked") 24 | 25 | 26 | if __name__ == "__main__": 27 | 28 | app = QApplication(sys.argv) 29 | button_and_label = ButtonAndLabel() 30 | button_and_label.show() 31 | sys.exit(app.exec_()) 32 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/button_and_list.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QWidget, QApplication, QLabel, QPushButton, QVBoxLayout 2 | from PySide2.QtCore import Qt 3 | import sys 4 | 5 | 6 | class ButtonAndList(QWidget): 7 | 8 | index = 0 9 | 10 | def __init__(self): 11 | super(ButtonAndList, self).__init__() 12 | 13 | self.button = QPushButton("button") 14 | self.button.clicked.connect(self.buttonClicked) 15 | 16 | self.v_layout = QVBoxLayout() 17 | 18 | layout = QVBoxLayout() 19 | layout.addWidget(self.button) 20 | layout.addLayout(self.v_layout) 21 | 22 | self.setLayout(layout) 23 | 24 | def buttonClicked(self): 25 | self.index += 1 26 | label = QLabel(str(self.index)) 27 | self.v_layout.addWidget(label) 28 | 29 | 30 | if __name__ == "__main__": 31 | 32 | app = QApplication(sys.argv) 33 | button_and_list = ButtonAndList() 34 | button_and_list.show() 35 | sys.exit(app.exec_()) 36 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/button_and_long_process.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QWidget, QApplication, QLabel, QPushButton, QVBoxLayout 2 | from PySide2.QtCore import Qt, QThread, Signal 3 | import sys 4 | from time import sleep 5 | 6 | 7 | class LongProcessThread(QThread): 8 | 9 | transaction = Signal() 10 | 11 | def __init__(self, parent=None): 12 | super(LongProcessThread, self).__init__(parent) 13 | 14 | def run(self): 15 | sleep(3) 16 | self.transaction.emit() 17 | 18 | 19 | class ButtonAndLongProcess(QWidget): 20 | 21 | def __init__(self): 22 | super(ButtonAndLongProcess, self).__init__() 23 | 24 | self.button = QPushButton("button") 25 | self.button.clicked.connect(self.buttonClicked) 26 | 27 | self.label = QLabel("label: before clicked") 28 | 29 | layout = QVBoxLayout() 30 | layout.addWidget(self.button) 31 | layout.addWidget(self.label) 32 | 33 | self.setLayout(layout) 34 | 35 | self.long_process_thread = LongProcessThread() 36 | self.long_process_thread.transaction.connect(self.afterLongProcess) 37 | 38 | def afterLongProcess(self): 39 | self.label.setText("label: after clicked") 40 | 41 | def buttonClicked(self): 42 | self.long_process_thread.start() 43 | 44 | 45 | if __name__ == "__main__": 46 | 47 | app = QApplication(sys.argv) 48 | button_and_long_process = ButtonAndLongProcess() 49 | button_and_long_process.show() 50 | sys.exit(app.exec_()) 51 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/button_with_sizepolicy.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QWidget, QApplication, QPushButton, QVBoxLayout, QSizePolicy 2 | from PySide2.QtCore import Qt 3 | import sys 4 | 5 | 6 | class ButtonWithSizePolicy(QWidget): 7 | 8 | def __init__(self): 9 | super(ButtonWithSizePolicy, self).__init__() 10 | 11 | button1 = QPushButton("button default") 12 | button2 = QPushButton("button maximum") 13 | button2.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 14 | button3 = QPushButton("button preferred") 15 | button3.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) 16 | button4 = QPushButton("button expanding") 17 | button4.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) 18 | button5 = QPushButton("button minimum") 19 | button5.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) 20 | button6 = QPushButton("button minimum expanding") 21 | button6.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) 22 | 23 | layout = QVBoxLayout() 24 | layout.addWidget(button1) 25 | layout.addWidget(button2) 26 | layout.addWidget(button3) 27 | layout.addWidget(button4) 28 | layout.addWidget(button5) 29 | layout.addWidget(button6) 30 | 31 | self.setLayout(layout) 32 | 33 | 34 | if __name__ == "__main__": 35 | 36 | app = QApplication(sys.argv) 37 | button_with_size_policy_widget = ButtonWithSizePolicy() 38 | button_with_size_policy_widget.resize(500, 200) 39 | button_with_size_policy_widget.show() 40 | sys.exit(app.exec_()) 41 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/combobox_and_label.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QWidget, QApplication, QLabel, QComboBox, QVBoxLayout 2 | from PySide2.QtCore import Qt 3 | import sys 4 | 5 | 6 | class ComboBoxAndLabel(QWidget): 7 | 8 | def __init__(self): 9 | super(ComboBoxAndLabel, self).__init__() 10 | 11 | self.combobox = QComboBox() 12 | self.combobox.addItems(["Orange", "Apple", "Grape"]) 13 | self.combobox.currentTextChanged.connect(self.comboboxSelected) 14 | 15 | self.label = QLabel("label: before selecting combobox") 16 | 17 | layout = QVBoxLayout() 18 | layout.addWidget(self.combobox) 19 | layout.addWidget(self.label) 20 | 21 | self.setLayout(layout) 22 | 23 | def comboboxSelected(self, value): 24 | self.label.setText(value) 25 | 26 | 27 | if __name__ == "__main__": 28 | 29 | app = QApplication(sys.argv) 30 | combobox_and_label = ComboBoxAndLabel() 31 | combobox_and_label.show() 32 | sys.exit(app.exec_()) 33 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/create_grid_window.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QWidget, QApplication, QLabel, QGridLayout 2 | from PySide2.QtCore import Qt 3 | import sys 4 | 5 | 6 | class GridWindow(QWidget): 7 | 8 | def __init__(self): 9 | super(GridWindow, self).__init__() 10 | 11 | layout = QGridLayout() 12 | 13 | label = QLabel("Label A") 14 | layout.addWidget(label, 0, 0) 15 | 16 | label = QLabel("Label B") 17 | layout.addWidget(label, 1, 0) 18 | 19 | label = QLabel("Label C") 20 | layout.addWidget(label, 2, 0) 21 | 22 | label = QLabel("Label D") 23 | layout.addWidget(label, 3, 0) 24 | 25 | label = QLabel("Label E") 26 | layout.addWidget(label, 0, 1) 27 | 28 | label = QLabel("Label F") 29 | layout.addWidget(label, 0, 2) 30 | 31 | label = QLabel("Label G") 32 | label.setAlignment(Qt.AlignCenter) 33 | layout.addWidget(label, 1, 1, 2, 2) 34 | 35 | self.setLayout(layout) 36 | 37 | 38 | if __name__ == "__main__": 39 | 40 | app = QApplication(sys.argv) 41 | gridWindow = GridWindow() 42 | gridWindow.show() 43 | sys.exit(app.exec_()) 44 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/tabbed_window.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QTabWidget, QApplication, QWidget 2 | import sys 3 | from button_and_label import ButtonAndLabel 4 | 5 | 6 | class TabbedWindow(QTabWidget): 7 | 8 | def __init__(self, parent=None): 9 | super(TabbedWindow, self).__init__(parent) 10 | widget1 = QWidget() 11 | self.widget2 = ButtonAndLabel() 12 | widget3 = QWidget() 13 | self.addTab(widget1, "Tab 1") 14 | self.addTab(self.widget2, "Tab 2") 15 | self.addTab(widget3, "Tab 3") 16 | 17 | 18 | if __name__ == "__main__": 19 | 20 | app = QApplication(sys.argv) 21 | tabbedWindow = TabbedWindow() 22 | tabbedWindow.show() 23 | sys.exit(app.exec_()) 24 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/test_button_and_dialog.py: -------------------------------------------------------------------------------- 1 | from button_and_dialog import ButtonAndDialog 2 | from PySide2.QtWidgets import QInputDialog 3 | from PySide2 import QtCore 4 | 5 | 6 | def test_button_and_dialog(qtbot, monkeypatch): 7 | widget = ButtonAndDialog() 8 | qtbot.addWidget(widget) 9 | 10 | monkeypatch.setattr(QInputDialog, 'getText', lambda *args: ("New Text", True)) 11 | qtbot.mouseClick(widget.button, QtCore.Qt.LeftButton) 12 | 13 | assert widget.label.text() == "New Text" 14 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/test_button_and_label.py: -------------------------------------------------------------------------------- 1 | from button_and_label import ButtonAndLabel 2 | from PySide2 import QtCore 3 | 4 | 5 | def test_button_and_label(qtbot): 6 | widget = ButtonAndLabel() 7 | qtbot.addWidget(widget) 8 | 9 | assert widget.label.text() == "label: before clicked" 10 | 11 | qtbot.mouseClick(widget.button, QtCore.Qt.LeftButton) 12 | 13 | assert widget.label.text() == "label: after clicked" 14 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/test_button_and_list.py: -------------------------------------------------------------------------------- 1 | from button_and_list import ButtonAndList 2 | from PySide2 import QtCore 3 | 4 | 5 | def test_button_and_list(qtbot): 6 | widget = ButtonAndList() 7 | qtbot.addWidget(widget) 8 | 9 | qtbot.mouseClick(widget.button, QtCore.Qt.LeftButton) 10 | qtbot.mouseClick(widget.button, QtCore.Qt.LeftButton) 11 | qtbot.mouseClick(widget.button, QtCore.Qt.LeftButton) 12 | 13 | label_item = widget.v_layout.takeAt(2) 14 | assert label_item.widget().text() == "3" 15 | 16 | label_item = widget.v_layout.takeAt(1) 17 | assert label_item.widget().text() == "2" 18 | 19 | label_item = widget.v_layout.takeAt(0) 20 | assert label_item.widget().text() == "1" 21 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/test_button_and_long_process.py: -------------------------------------------------------------------------------- 1 | from button_and_long_process import ButtonAndLongProcess 2 | from PySide2 import QtCore 3 | 4 | 5 | def test_button_and_long_process(qtbot): 6 | widget = ButtonAndLongProcess() 7 | qtbot.addWidget(widget) 8 | 9 | assert widget.label.text() == "label: before clicked" 10 | 11 | qtbot.mouseClick(widget.button, QtCore.Qt.LeftButton) 12 | 13 | def check_label(): 14 | assert widget.label.text() == "label: after clicked" 15 | 16 | qtbot.waitUntil(check_label, 4000) 17 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/test_combobox_and_label.py: -------------------------------------------------------------------------------- 1 | from combobox_and_label import ComboBoxAndLabel 2 | from PySide2 import QtCore 3 | 4 | 5 | def test_combobox_and_label(qtbot): 6 | widget = ComboBoxAndLabel() 7 | qtbot.addWidget(widget) 8 | 9 | assert widget.label.text() == "label: before selecting combobox" 10 | 11 | qtbot.keyClicks(widget.combobox, "Grape") 12 | 13 | assert widget.label.text() == "Grape" 14 | -------------------------------------------------------------------------------- /Chapter09/advanced_course_qt/test_tabbed_window.py: -------------------------------------------------------------------------------- 1 | from tabbed_window import TabbedWindow 2 | from PySide2 import QtCore 3 | 4 | 5 | def test_tabbed_window(qtbot): 6 | tabbed = TabbedWindow() 7 | qtbot.addWidget(tabbed) 8 | 9 | assert tabbed.widget2.label.text() == "label: before clicked" 10 | 11 | qtbot.mouseClick(tabbed.widget2.button, QtCore.Qt.LeftButton) 12 | 13 | assert tabbed.widget2.label.text() == "label: after clicked" 14 | -------------------------------------------------------------------------------- /Chapter09/chains/contracts/ERC20Token.vy: -------------------------------------------------------------------------------- 1 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) 2 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) 3 | 4 | name: public(bytes[10]) 5 | symbol: public(bytes[3]) 6 | totalSupply: public(uint256) 7 | decimals: public(uint256) 8 | balances: uint256[address] 9 | allowed: uint256[address][address] 10 | 11 | @public 12 | def __init__(): 13 | _initialSupply: uint256 = 1000 14 | _decimals: uint256 = 3 15 | self.totalSupply = _initialSupply * 10 ** _decimals 16 | self.balances[msg.sender] = self.totalSupply 17 | self.name = 'Haha Coin' 18 | self.symbol = 'HAH' 19 | self.decimals = _decimals 20 | log.Transfer(ZERO_ADDRESS, msg.sender, self.totalSupply) 21 | 22 | @public 23 | @constant 24 | def balanceOf(_owner: address) -> uint256: 25 | return self.balances[_owner] 26 | 27 | @public 28 | def transfer(_to: address, _amount: uint256) -> bool: 29 | assert self.balances[msg.sender] >= _amount 30 | self.balances[msg.sender] -= _amount 31 | self.balances[_to] += _amount 32 | log.Transfer(msg.sender, _to, _amount) 33 | 34 | return True 35 | 36 | @public 37 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool: 38 | assert _value <= self.allowed[_from][msg.sender] 39 | assert _value <= self.balances[_from] 40 | 41 | self.balances[_from] -= _value 42 | self.allowed[_from][msg.sender] -= _value 43 | self.balances[_to] += _value 44 | log.Transfer(_from, _to, _value) 45 | 46 | return True 47 | 48 | @public 49 | def approve(_spender: address, _amount: uint256) -> bool: 50 | self.allowed[msg.sender][_spender] = _amount 51 | log.Approval(msg.sender, _spender, _amount) 52 | 53 | return True 54 | 55 | @public 56 | @constant 57 | def allowance(_owner: address, _spender: address) -> uint256: 58 | return self.allowed[_owner][_spender] 59 | -------------------------------------------------------------------------------- /Chapter09/chains/contracts/ERC20Token2.vy: -------------------------------------------------------------------------------- 1 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) 2 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) 3 | 4 | name: public(bytes[10]) 5 | symbol: public(bytes[3]) 6 | totalSupply: public(uint256) 7 | decimals: public(uint256) 8 | balances: uint256[address] 9 | allowed: uint256[address][address] 10 | 11 | @public 12 | def __init__(): 13 | _initialSupply: uint256 = 2000 14 | _decimals: uint256 = 3 15 | self.totalSupply = _initialSupply * 10 ** _decimals 16 | self.balances[msg.sender] = self.totalSupply 17 | self.name = 'Momo Coin' 18 | self.symbol = 'MOM' 19 | self.decimals = _decimals 20 | log.Transfer(ZERO_ADDRESS, msg.sender, self.totalSupply) 21 | 22 | @public 23 | @constant 24 | def balanceOf(_owner: address) -> uint256: 25 | return self.balances[_owner] 26 | 27 | @public 28 | def transfer(_to: address, _amount: uint256) -> bool: 29 | assert self.balances[msg.sender] >= _amount 30 | self.balances[msg.sender] -= _amount 31 | self.balances[_to] += _amount 32 | log.Transfer(msg.sender, _to, _amount) 33 | 34 | return True 35 | 36 | @public 37 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool: 38 | assert _value <= self.allowed[_from][msg.sender] 39 | assert _value <= self.balances[_from] 40 | 41 | self.balances[_from] -= _value 42 | self.allowed[_from][msg.sender] -= _value 43 | self.balances[_to] += _value 44 | log.Transfer(_from, _to, _value) 45 | 46 | return True 47 | 48 | @public 49 | def approve(_spender: address, _amount: uint256) -> bool: 50 | self.allowed[msg.sender][_spender] = _amount 51 | log.Approval(msg.sender, _spender, _amount) 52 | 53 | return True 54 | 55 | @public 56 | @constant 57 | def allowance(_owner: address, _spender: address) -> uint256: 58 | return self.allowed[_owner][_spender] 59 | -------------------------------------------------------------------------------- /Chapter09/chains/localblock/genesis.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 4 | "coinbase": "0x427af7b53b8f56adf6f13932bb17c42ed2a53d04", 5 | "extraData": "0x686f727365", 6 | "config": { 7 | "daoForkBlock": 0, 8 | "daoForSupport": true, 9 | "homesteadBlock": 0 10 | }, 11 | "timestamp": "0x0", 12 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 13 | "nonce": "0xdeadbeefdeadbeef", 14 | "alloc": { 15 | "0x427af7b53b8f56adf6f13932bb17c42ed2a53d04":{ 16 | "balance": "1000000000000000000000000000000" 17 | } 18 | }, 19 | "gasLimit": "0x47d5cc", 20 | "difficulty": "0x01" 21 | } 22 | -------------------------------------------------------------------------------- /Chapter09/chains/localblock/init_chain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpcapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --ws --wsaddr 127.0.0.1 --wsport 8546 --wsapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --datadir /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_09/chains/blockchain/chain_data --maxpeers 0 --networkid 1234 --port 30303 --ipcpath /tmp/tmpn_ztv58q/geth.ipc --nodiscover --mine --minerthreads 1 init /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_09/chains/blockchain/genesis.json -------------------------------------------------------------------------------- /Chapter09/chains/localblock/password: -------------------------------------------------------------------------------- 1 | this-is-not-a-secure-password 2 | -------------------------------------------------------------------------------- /Chapter09/chains/localblock/run_chain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpcapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --ws --wsaddr 127.0.0.1 --wsport 8546 --wsapi admin,debug,eth,miner,net,personal,shh,txpool,web3,ws --datadir /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_09/chains/localblock/chain_data --maxpeers 0 --networkid 1234 --port 30303 --ipcpath /tmp/geth.ipc --unlock 0x427af7b53b8f56adf6f13932bb17c42ed2a53d04 --password /home/arjuna/Documents/WritingBook/hands-on-blockchain-for-python-developers/chapter_09/chains/localblock/password --nodiscover --mine --minerthreads 1 3 | -------------------------------------------------------------------------------- /Chapter09/chains/registrar.json: -------------------------------------------------------------------------------- 1 | { 2 | "deployments": { 3 | "blockchain://5112f234674aacf2daccbe21a36193e59c69e751b6eb89e57b755f72898942c9/block/127083555db85eb7e86f82ced0e1e898418cb986e6d4979fdb5bb07a6789c392": { 4 | "ERC20Token2": { 5 | "0x26Eb6cdC6968C34B96b9343FcdB7b2E2b1769579": { 6 | "timestamp": 1544368351655658 7 | } 8 | } 9 | }, 10 | "blockchain://5112f234674aacf2daccbe21a36193e59c69e751b6eb89e57b755f72898942c9/block/ba5cdfa837a99b7f34684726952078393ed9b590b7148aa73bdbe43cd1ec740b": { 11 | "ERC20Token": { 12 | "0xd3B78F72AcE42c89774e03011d738f84683A76B1": { 13 | "timestamp": 1544365532955736 14 | } 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Chapter09/wallet/address.txt: -------------------------------------------------------------------------------- 1 | 0xd3B78F72AcE42c89774e03011d738f84683A76B1 2 | 0x26Eb6cdC6968C34B96b9343FcdB7b2E2b1769579 3 | -------------------------------------------------------------------------------- /Chapter09/wallet/icons/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter09/wallet/icons/ajax-loader.gif -------------------------------------------------------------------------------- /Chapter09/wallet/icons/copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/wallet/images/427af7b53b8f56adf6f13932bb17c42ed2a53d04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter09/wallet/images/427af7b53b8f56adf6f13932bb17c42ed2a53d04.png -------------------------------------------------------------------------------- /Chapter09/wallet/images/6ad2ffd2e08bd73f5c50db60fdc82a58b0590b99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter09/wallet/images/6ad2ffd2e08bd73f5c50db60fdc82a58b0590b99.png -------------------------------------------------------------------------------- /Chapter09/wallet/tests/test_account.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/..")) 3 | 4 | from wallet import WalletWidget 5 | from PySide2.QtWidgets import QInputDialog 6 | from PySide2 import QtCore 7 | 8 | 9 | def test_account(qtbot, monkeypatch): 10 | wallet = WalletWidget() 11 | qtbot.addWidget(wallet) 12 | 13 | old_accounts_amount = wallet.account_widget.accounts_layout.count() 14 | 15 | monkeypatch.setattr(QInputDialog, 'getText', lambda *args: ("password", True)) 16 | qtbot.mouseClick(wallet.account_widget.create_account_button, QtCore.Qt.LeftButton) 17 | 18 | accounts_amount = wallet.account_widget.accounts_layout.count() 19 | assert accounts_amount == old_accounts_amount + 1 20 | 21 | wallet.killThreads() 22 | -------------------------------------------------------------------------------- /Chapter09/wallet/tests/test_send.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/..")) 3 | from time import sleep 4 | 5 | from wallet import WalletWidget 6 | from PySide2.QtWidgets import QInputDialog 7 | from PySide2 import QtCore 8 | 9 | 10 | def test_send(qtbot, monkeypatch): 11 | wallet = WalletWidget() 12 | qtbot.addWidget(wallet) 13 | 14 | monkeypatch.setattr(QInputDialog, 'getText', lambda *args: ("this-is-not-a-secure-password", True)) 15 | 16 | first_account = wallet.send_widget.sender_items[0] 17 | second_account = wallet.send_widget.sender_items[1] 18 | 19 | qtbot.keyClicks(wallet.send_widget.sender_combo_box, second_account) 20 | old_balance_of_second_account = int(float(wallet.send_widget.balance_label.text().split()[1])) 21 | sleep(1) 22 | 23 | qtbot.keyClicks(wallet.send_widget.destination_line_edit, second_account) 24 | sleep(1) 25 | 26 | qtbot.keyClicks(wallet.send_widget.sender_combo_box, first_account) 27 | sleep(1) 28 | 29 | qtbot.keyClicks(wallet.send_widget.amount_line_edit, "10") 30 | sleep(1) 31 | 32 | qtbot.mouseClick(wallet.send_widget.send_button, QtCore.Qt.LeftButton) 33 | 34 | sleep(20) 35 | 36 | qtbot.keyClicks(wallet.send_widget.sender_combo_box, second_account) 37 | balance_of_second_account = int(float(wallet.send_widget.balance_label.text().split()[1])) 38 | 39 | assert balance_of_second_account - old_balance_of_second_account == 10 40 | 41 | wallet.killThreads() 42 | -------------------------------------------------------------------------------- /Chapter09/wallet/tests/test_token.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/..")) 3 | 4 | from wallet import WalletWidget 5 | from PySide2.QtWidgets import QInputDialog 6 | from PySide2 import QtCore 7 | 8 | 9 | def test_token(qtbot, monkeypatch): 10 | wallet = WalletWidget() 11 | qtbot.addWidget(wallet) 12 | 13 | old_tokens_amount = wallet.token_widget.tokens_layout.count() 14 | 15 | address = None 16 | with open('address.txt') as f: 17 | address = f.readline().rstrip() 18 | 19 | monkeypatch.setattr(QInputDialog, 'getText', lambda *args: (address, True)) 20 | qtbot.mouseClick(wallet.token_widget.watch_token_button, QtCore.Qt.LeftButton) 21 | 22 | tokens_amount = wallet.token_widget.tokens_layout.count() 23 | assert tokens_amount == old_tokens_amount + 1 24 | 25 | wallet.killThreads() 26 | -------------------------------------------------------------------------------- /Chapter09/wallet/tools/util.py: -------------------------------------------------------------------------------- 1 | from os.path import isdir, exists 2 | from os import mkdir 3 | from tools.identicon import render_identicon 4 | 5 | 6 | def render_avatar(code): 7 | code = int(code, 16) 8 | img_filename = 'images/%08x.png' % code 9 | if exists(img_filename): 10 | return img_filename 11 | img = render_identicon(code, 24) 12 | if not isdir('images'): 13 | mkdir('images') 14 | img.save(img_filename, 'PNG') 15 | return img_filename 16 | -------------------------------------------------------------------------------- /Chapter09/wallet/wallet.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QTabWidget, QApplication 2 | import sys 3 | 4 | from wallet_widgets.account_widget import AccountWidget 5 | from wallet_widgets.send_widget import SendWidget 6 | from wallet_widgets.token_widget import TokenWidget 7 | 8 | 9 | class WalletWidget(QTabWidget): 10 | 11 | def __init__(self, parent=None): 12 | super(WalletWidget, self).__init__(parent) 13 | self.account_widget = AccountWidget() 14 | self.send_widget = SendWidget() 15 | self.token_widget = TokenWidget() 16 | self.addTab(self.account_widget, "Account") 17 | self.addTab(self.send_widget, "Send") 18 | self.addTab(self.token_widget, "Token") 19 | 20 | def killThreads(self): 21 | self.account_widget.kill() 22 | 23 | 24 | if __name__ == "__main__": 25 | 26 | app = QApplication(sys.argv) 27 | wallet_widget = WalletWidget() 28 | wallet_widget.show() 29 | return_app = app.exec_() 30 | wallet_widget.killThreads() 31 | sys.exit(return_app) 32 | -------------------------------------------------------------------------------- /Chapter09/wallet/wallet_threads/balance_thread.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtCore import QThread, Signal 2 | from time import sleep 3 | from blockchain import blockchain 4 | 5 | 6 | class BalanceThread(QThread): 7 | 8 | get_balance_transaction = Signal(map) 9 | 10 | def __init__(self, parent=None): 11 | super(BalanceThread, self).__init__(parent) 12 | self.quit = False 13 | 14 | def kill(self): 15 | self.quit = True 16 | 17 | def run(self): 18 | while True: 19 | sleep(2) 20 | if self.quit: 21 | break 22 | accounts = blockchain.get_accounts() 23 | self.get_balance_transaction.emit(accounts) 24 | -------------------------------------------------------------------------------- /Chapter09/wallet/wallet_threads/send_thread.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtCore import QThread, Signal 2 | from blockchain import blockchain 3 | 4 | 5 | class SendThread(QThread): 6 | 7 | send_transaction = Signal() 8 | 9 | def __init__(self, parent=None): 10 | super(SendThread, self).__init__(parent) 11 | 12 | def prepareTransaction(self, tx): 13 | self.tx = tx 14 | 15 | def run(self): 16 | blockchain.create_send_transaction(self.tx) 17 | self.send_transaction.emit() 18 | -------------------------------------------------------------------------------- /Chapter09/wallet/wallet_threads/send_token_thread.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtCore import QThread, Signal 2 | from blockchain import blockchain 3 | 4 | 5 | class SendTokenThread(QThread): 6 | 7 | send_token_transaction = Signal() 8 | 9 | def __init__(self, parent=None): 10 | super(SendTokenThread, self).__init__(parent) 11 | 12 | def prepareTransaction(self, tx, token_information): 13 | self.tx = tx 14 | self.token_information = token_information 15 | 16 | def run(self): 17 | blockchain.create_send_token_transaction(self.tx, self.token_information) 18 | self.send_token_transaction.emit() 19 | -------------------------------------------------------------------------------- /Chapter09/wallet/wallet_widgets/account_widget.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import (QWidget, 2 | QGridLayout, 3 | QVBoxLayout, 4 | QHBoxLayout, 5 | QPushButton, 6 | QLabel, 7 | QInputDialog, 8 | QLineEdit, 9 | QToolTip, 10 | QApplication, 11 | QSizePolicy) 12 | from PySide2.QtCore import Slot, SIGNAL, QSize 13 | from PySide2.QtGui import QPixmap, QIcon, QCursor, QClipboard 14 | from time import sleep 15 | from blockchain import blockchain 16 | from tools.util import render_avatar 17 | from wallet_threads.balance_thread import BalanceThread 18 | 19 | 20 | class AccountWidget(QWidget): 21 | 22 | balance_widgets = {} 23 | 24 | def __init__(self, parent=None): 25 | super(AccountWidget, self).__init__(parent) 26 | 27 | self.create_account_button = QPushButton("Create Account") 28 | self.create_account_button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 29 | self.connect(self.create_account_button, SIGNAL('clicked()'), self.createNewAccount) 30 | 31 | self.accounts_layout = QVBoxLayout() 32 | 33 | accounts = blockchain.get_accounts() 34 | 35 | for account, balance in accounts: 36 | self._addAccountToWindow(account, balance) 37 | 38 | layout = QGridLayout() 39 | 40 | layout.addWidget(self.create_account_button, 0, 0) 41 | layout.addLayout(self.accounts_layout, 1, 0) 42 | 43 | self.setLayout(layout) 44 | 45 | self.balance_thread = BalanceThread() 46 | self.balance_thread.get_balance_transaction.connect(self._updateBalances) 47 | self.balance_thread.start() 48 | 49 | @Slot() 50 | def createNewAccount(self): 51 | password, ok = QInputDialog.getText(self, "Create A New Account", 52 | "Password:", QLineEdit.Normal) 53 | if ok and password != '': 54 | new_account = blockchain.create_new_account(password) 55 | self._addAccountToWindow(new_account, 0, resize_parent=True) 56 | 57 | def copyAddress(self, address): 58 | QToolTip.showText(QCursor.pos(), "Address %s has been copied to clipboard!" % address) 59 | clipboard = QApplication.clipboard() 60 | clipboard.setText(address) 61 | 62 | def _addAccountToWindow(self, account, balance, resize_parent=False): 63 | wrapper_layout = QVBoxLayout() 64 | account_layout = QHBoxLayout() 65 | rows_layout = QVBoxLayout() 66 | address_layout = QHBoxLayout() 67 | account_label = QLabel(account) 68 | account_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 69 | copy_button = QPushButton() 70 | copy_button.setAutoFillBackground(True) 71 | copy_button.setIcon(QIcon('icons/copy.svg')) 72 | self.connect(copy_button, SIGNAL('clicked()'), lambda: self.copyAddress(account)) 73 | address_layout.addWidget(account_label) 74 | address_layout.addWidget(copy_button) 75 | balance_label = QLabel('Balance: %.5f ethers' % balance) 76 | balance_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 77 | self.balance_widgets[account] = balance_label 78 | rows_layout.addLayout(address_layout) 79 | rows_layout.addWidget(balance_label) 80 | avatar = QLabel() 81 | img_filename = render_avatar(account) 82 | pixmap = QPixmap(img_filename) 83 | avatar.setPixmap(pixmap) 84 | account_layout.addWidget(avatar) 85 | account_layout.addLayout(rows_layout) 86 | wrapper_layout.addLayout(account_layout) 87 | wrapper_layout.addSpacing(20) 88 | self.accounts_layout.addLayout(wrapper_layout) 89 | 90 | if resize_parent: 91 | sizeHint = self.sizeHint() 92 | self.parentWidget().parentWidget().resize(QSize(sizeHint.width(), sizeHint.height() + 40)) 93 | 94 | def kill(self): 95 | self.balance_thread.kill() 96 | sleep(2) 97 | 98 | @Slot() 99 | def _updateBalances(self, accounts): 100 | for account, balance in accounts: 101 | self.balance_widgets[account].setText('Balance: %.5f ethers' % balance) 102 | -------------------------------------------------------------------------------- /Chapter09/wallet/wallet_widgets/token_widget.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import (QWidget, 2 | QGridLayout, 3 | QVBoxLayout, 4 | QHBoxLayout, 5 | QPushButton, 6 | QLabel, 7 | QInputDialog, 8 | QLineEdit, 9 | QToolTip, 10 | QComboBox, 11 | QApplication, 12 | QSlider, 13 | QSizePolicy) 14 | from PySide2.QtCore import Slot, SIGNAL, QSize, Qt 15 | from PySide2.QtGui import QPixmap, QMovie, QPalette, QColor 16 | from os.path import isdir, exists 17 | from os import mkdir 18 | from time import sleep 19 | import json 20 | from tools.util import render_avatar 21 | from blockchain import blockchain, SendTransaction, TokenInformation 22 | 23 | 24 | class TokenWidget(QWidget): 25 | 26 | tokens_file = 'tokens.json' 27 | 28 | def __init__(self, parent=None): 29 | super(TokenWidget, self).__init__(parent) 30 | 31 | self.watch_token_button = QPushButton("Watch Token") 32 | 33 | tokens = blockchain.get_tokens() 34 | 35 | self.tokens_layout = QVBoxLayout() 36 | 37 | for address, token_from_json in tokens.items(): 38 | token_information = blockchain.get_token_named_tuple(token_from_json, address) 39 | self._addTokenToWindow(token_information) 40 | 41 | layout = QGridLayout() 42 | 43 | self.watch_token_button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 44 | self.connect(self.watch_token_button, SIGNAL('clicked()'), self.watchNewToken) 45 | 46 | layout.addWidget(self.watch_token_button, 0, 0) 47 | layout.addLayout(self.tokens_layout, 1, 0) 48 | 49 | self.setLayout(layout) 50 | 51 | def _addTokenToWindow(self, token_information, resize_parent=False): 52 | wrapper_layout = QVBoxLayout() 53 | token_layout = QHBoxLayout() 54 | rows_layout = QVBoxLayout() 55 | token_label = QLabel(token_information.name) 56 | token_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 57 | symbol_label = QLabel(token_information.symbol) 58 | symbol_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 59 | total_supply_label = QLabel('Total Supply: %d coins' % token_information.totalSupply) 60 | total_supply_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 61 | rows_layout.addWidget(token_label) 62 | rows_layout.addWidget(symbol_label) 63 | rows_layout.addWidget(total_supply_label) 64 | avatar = QLabel() 65 | img_filename = render_avatar(token_information.address) 66 | pixmap = QPixmap(img_filename) 67 | avatar.setPixmap(pixmap) 68 | token_layout.addWidget(avatar) 69 | token_layout.addLayout(rows_layout) 70 | wrapper_layout.addLayout(token_layout) 71 | wrapper_layout.addSpacing(20) 72 | self.tokens_layout.addLayout(wrapper_layout) 73 | 74 | if resize_parent: 75 | sizeHint = self.size() 76 | self.parentWidget().parentWidget().resize(QSize(sizeHint.width(), sizeHint.height() + 100)) 77 | 78 | @Slot() 79 | def watchNewToken(self): 80 | address, ok = QInputDialog.getText(self, "Watch A New Token", 81 | "Token Smart Contract:", QLineEdit.Normal) 82 | if ok and address != '': 83 | token_information = blockchain.get_information_of_token(address) 84 | self._addTokenToWindow(token_information, resize_parent=True) 85 | token_data = {} 86 | if exists(self.tokens_file): 87 | with open(self.tokens_file) as json_data: 88 | token_data = json.load(json_data) 89 | token_data[token_information.address] = {'name': token_information.name, 90 | 'symbol': token_information.symbol, 91 | 'total_supply': token_information.totalSupply} 92 | with open(self.tokens_file, 'w') as outfile: 93 | json.dump(token_data, outfile) 94 | -------------------------------------------------------------------------------- /Chapter10/create_hash_from_content.py: -------------------------------------------------------------------------------- 1 | from os import listdir 2 | from hashlib import sha256 3 | 4 | 5 | files = [f for f in listdir('.') if 'hello' in f] 6 | 7 | hashes = {} 8 | 9 | for file in files: 10 | with open(file) as f: 11 | content = f.read().encode('utf-8') 12 | hash_of_content = sha256(content).hexdigest() 13 | hashes[hash_of_content] = content 14 | 15 | content = hashes['20c38a7a55fc8a8e7f45fde7247a0436d97826c20c5e7f8c978e6d59fa895fd2'] 16 | print(content.decode('utf-8')) 17 | 18 | print(len(hashes)) 19 | -------------------------------------------------------------------------------- /Chapter10/hash_big_file.py: -------------------------------------------------------------------------------- 1 | from os import listdir 2 | from hashlib import sha256 3 | from merkle_tree import MerkleTree 4 | 5 | 6 | hashes = {} 7 | 8 | file = 'hello_big.txt' 9 | with open(file) as f: 10 | lines = f.read().split('\n') 11 | hash = [] 12 | hash_of_hash = [] 13 | merkle_tree = MerkleTree(lines) 14 | root_hash = merkle_tree.root_hash 15 | 16 | hashes[root_hash] = [] 17 | for line in lines: 18 | hashes[root_hash].append(line) 19 | 20 | print(hashes) 21 | -------------------------------------------------------------------------------- /Chapter10/hash_directory.py: -------------------------------------------------------------------------------- 1 | from merkle_dag import MerkleDAGNode 2 | 3 | 4 | outer_directory = 'sample_directory' 5 | 6 | node = MerkleDAGNode(outer_directory) 7 | print(node) 8 | print(node.content) 9 | -------------------------------------------------------------------------------- /Chapter10/hello.txt: -------------------------------------------------------------------------------- 1 | I am a good boy. 2 | -------------------------------------------------------------------------------- /Chapter10/hello2.txt: -------------------------------------------------------------------------------- 1 | I am a good girl. 2 | -------------------------------------------------------------------------------- /Chapter10/hello3.txt: -------------------------------------------------------------------------------- 1 | I am a good horse. 2 | -------------------------------------------------------------------------------- /Chapter10/hello4.txt: -------------------------------------------------------------------------------- 1 | I am a good girl. 2 | -------------------------------------------------------------------------------- /Chapter10/hello_big.txt: -------------------------------------------------------------------------------- 1 | I am a big boy. 2 | I am a tall girl. 3 | I am a fast horse. 4 | I am a slow dragon. 5 | -------------------------------------------------------------------------------- /Chapter10/merkle_dag.py: -------------------------------------------------------------------------------- 1 | from os import listdir 2 | from hashlib import sha256 3 | from os.path import isdir 4 | from pathlib import Path 5 | from merkle_tree import MerkleTree 6 | 7 | 8 | class MerkleDAGNode: 9 | 10 | def __init__(self, filepath : str): 11 | self.pointers = {} 12 | self.dirtype = isdir(filepath) 13 | self.filename = Path(filepath).name 14 | if not self.dirtype: 15 | with open(filepath) as f: 16 | self.content = f.read() 17 | self.hash = self._hash((self.filename + self.content).encode('utf-8')) 18 | else: 19 | self.content = self._iterate_directory_contents(filepath) 20 | nodes_in_str_array = list(map(lambda x: str(x), self.content)) 21 | if nodes_in_str_array: 22 | self.hash = self._hash((self.filename + MerkleTree(nodes_in_str_array).root_hash).encode('utf-8')) 23 | else: 24 | self.hash = self._hash(self.filename.encode('utf-8')) 25 | 26 | def _hash(self, data : bytes) -> bytes: 27 | return sha256(data).hexdigest() 28 | 29 | def _iterate_directory_contents(self, directory : str): 30 | nodes = [] 31 | for f in listdir(directory): 32 | merkle_dag_node = MerkleDAGNode(directory + '/' + f) 33 | nodes.append(merkle_dag_node) 34 | self.pointers[f] = merkle_dag_node 35 | return nodes 36 | 37 | def __repr__(self): 38 | return 'MerkleDAGNode: ' + self.hash + ' || ' + self.filename 39 | 40 | def __eq__(self, other): 41 | if isinstance(other, MerkleDAGNode): 42 | return self.hash == other.hash 43 | return False 44 | -------------------------------------------------------------------------------- /Chapter10/merkle_tree.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha256 2 | from typing import List 3 | from math import ceil 4 | 5 | 6 | class MerkleTree: 7 | 8 | def __init__(self, leaf_nodes : List[str]): 9 | self.hash_nodes : List[str] = [] 10 | self.leaf_nodes : List[str] = leaf_nodes 11 | self._turn_leaf_nodes_to_hash_nodes() 12 | if len(leaf_nodes) < 4: 13 | self.root_hash = self._hash_list() 14 | else: 15 | self.root_hash = self._build_root_hash() 16 | 17 | def _hash_list(self): 18 | long_node = "".join(self.hash_nodes) 19 | return self._hash(long_node.encode('utf-8')) 20 | 21 | def _turn_leaf_nodes_to_hash_nodes(self): 22 | for node in self.leaf_nodes: 23 | self.hash_nodes.append(self._hash(node.encode('utf-8'))) 24 | 25 | def _hash(self, data : bytes) -> bytes: 26 | return sha256(data).hexdigest() 27 | 28 | def _build_root_hash(self) -> bytes: 29 | parent_amount = ceil(len(self.hash_nodes) / 2) 30 | nodes : List[str] = self.hash_nodes 31 | 32 | while parent_amount > 1: 33 | parents : List[bytes] = [] 34 | i = 0 35 | while i < len(nodes): 36 | node1 = nodes[i] 37 | if i + 1 >= len(nodes): 38 | node2 = None 39 | else: 40 | node2 = nodes[i+1] 41 | parents.append(self._convert_parent_from_two_nodes(node1, node2)) 42 | i += 2 43 | parent_amount = len(parents) 44 | nodes = parents 45 | 46 | return parents[0] 47 | 48 | def _convert_parent_from_two_nodes(self, node1 : bytes, node2) -> bytes: 49 | if node2 == None: 50 | return self._hash((node1 + node1).encode('utf-8')) 51 | return self._hash((node1 + node2).encode('utf-8')) 52 | 53 | 54 | if __name__ == '__main__': 55 | leaf_nodes = ['cat', 'dog', 'bird', 'whale'] 56 | merkle_tree = MerkleTree(leaf_nodes) 57 | # ba2b19423245563949658c3f98ebbc337671706e037267a7d95be78dc95f0f31 58 | print(merkle_tree.root_hash) 59 | 60 | leaf_nodes = ['cat', 'dog', 'bird', 'whale', 'unicorn', 'pegasus', 'elephant', 'mouse'] 61 | merkle_tree = MerkleTree(leaf_nodes) 62 | # 20a9a6aa60cc29d62189a5a4d2388a272b2a0f249264dd0da3a7eecdfdc044bd 63 | print(merkle_tree.root_hash) 64 | 65 | leaf_nodes = ['cat', 'dog', 'bird', 'whale', 'unicorn'] 66 | merkle_tree = MerkleTree(leaf_nodes) 67 | # 6182e4e70b821ecc35d788bb4801f9b26bec75e935129e3fcd66648a5fdd79f4 68 | print(merkle_tree.root_hash) 69 | 70 | leaf_nodes = ['cat', 'dog', 'bird', 'whale', 'unicorn', 'pegasus', 'elephant'] 71 | merkle_tree = MerkleTree(leaf_nodes) 72 | # 8149c6504e532f0b03631ab3779f44b4f72edcef7e842120fe2a9198fac8a08e 73 | print(merkle_tree.root_hash) 74 | 75 | leaf_nodes = ['cat', 'dog'] 76 | merkle_tree = MerkleTree(leaf_nodes) 77 | # d2cc68f933eebbeb605e65d4fa80ab8a76b87a40fce6fab348431f2f0c199603 78 | print(merkle_tree.root_hash) 79 | -------------------------------------------------------------------------------- /Chapter10/sample_directory/hello.txt: -------------------------------------------------------------------------------- 1 | I am a good boy. 2 | -------------------------------------------------------------------------------- /Chapter10/sample_directory/hello2.txt: -------------------------------------------------------------------------------- 1 | I am a good girl. 2 | -------------------------------------------------------------------------------- /Chapter10/sample_directory/hello3.txt: -------------------------------------------------------------------------------- 1 | I am a good horse. 2 | -------------------------------------------------------------------------------- /Chapter10/sample_directory/inner_directory/hello4.txt: -------------------------------------------------------------------------------- 1 | I am a good girl. 2 | -------------------------------------------------------------------------------- /Chapter10/test_merkle_dag_node.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from merkle_dag import MerkleDAGNode 3 | 4 | 5 | outer_directory = 'sample_directory' 6 | file1 = 'hello.txt' 7 | file2 = 'hello2.txt' 8 | file3 = 'hello3.txt' 9 | inner_directory = 'inner_directory' 10 | inner_file = 'hello4.txt' 11 | 12 | 13 | class TestMerkleDAGNode(unittest.TestCase): 14 | 15 | def test_file_node(self): 16 | file_node = MerkleDAGNode(outer_directory + '/' + file1) 17 | self.assertEqual(file_node.filename, file1) 18 | self.assertEqual(file_node.hash, '8ced218a323755a7d4969187449177bb2338658c354c7174e21285b579ae2bca') 19 | self.assertEqual(file_node.content, 'I am a good boy.\n') 20 | 21 | def test_directory_with_single_file_node(self): 22 | dir_node = MerkleDAGNode(outer_directory + '/' + inner_directory) 23 | self.assertEqual(dir_node.filename, inner_directory) 24 | self.assertEqual(dir_node.hash, 'c075280aef64223bd38b1bed1017599852180a37baa0eacce28bb92ac5492eb9') 25 | content_of_directory = [ 26 | MerkleDAGNode(outer_directory + '/' + inner_directory + '/' + inner_file), 27 | ] 28 | self.assertEqual(dir_node.content[0], content_of_directory[0]) 29 | 30 | def test_directory_with_multiple_files_and_single_directory_node(self): 31 | dir_node = MerkleDAGNode(outer_directory) 32 | self.assertEqual(dir_node.filename, outer_directory) 33 | self.assertEqual(dir_node.hash, 'ec618189b9de0dae250ab5fa0fd9bf1abc158935c66ff8595446f5f9b929e037') 34 | content_of_directory = [ 35 | MerkleDAGNode(outer_directory + '/' + file1), 36 | MerkleDAGNode(outer_directory + '/' + file2), 37 | MerkleDAGNode(outer_directory + '/' + file3), 38 | MerkleDAGNode(outer_directory + '/' + inner_directory) 39 | ] 40 | self.assertEqual(dir_node.pointers[file1], content_of_directory[0]) 41 | self.assertEqual(dir_node.pointers[file2], content_of_directory[1]) 42 | self.assertEqual(dir_node.pointers[file3], content_of_directory[2]) 43 | self.assertEqual(dir_node.pointers[inner_directory], content_of_directory[3]) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /Chapter11/add_directory.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | import pprint 3 | 4 | 5 | c = ipfsapi.connect() 6 | result = c.add('mysite', True) 7 | 8 | pp = pprint.PrettyPrinter(indent=2) 9 | pp.pprint(result) 10 | -------------------------------------------------------------------------------- /Chapter11/add_file.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | result = c.add('hello.txt') 6 | 7 | print(result) 8 | -------------------------------------------------------------------------------- /Chapter11/add_horoscope_predictions.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | result = c.add('horoscope1.txt') 6 | print(result) 7 | result = c.add('horoscope2.txt') 8 | print(result) 9 | -------------------------------------------------------------------------------- /Chapter11/add_image_file.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | 6 | result = c.add('milada-vigerova-1284157-unsplash.jpg') 7 | print(result) 8 | -------------------------------------------------------------------------------- /Chapter11/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter11/cat.jpg -------------------------------------------------------------------------------- /Chapter11/cat_cute_cat.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | result = c.cat('QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg') 6 | with open('cat.jpg', 'wb') as f: 7 | f.write(result) 8 | -------------------------------------------------------------------------------- /Chapter11/construct_image_from_blocks.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | 6 | images_bytes = [] 7 | 8 | blocks = c.ls('QmV5KPoHHqbq2NsALniERnaYjCJPi3UxLnpwdTkV1EbNZM') 9 | for block in blocks['Objects'][0]['Links']: 10 | bytes = c.cat(block['Hash']) 11 | images_bytes.append(bytes) 12 | 13 | images = b''.join(images_bytes) 14 | with open('image_from_blocks.jpg', 'wb') as f: 15 | f.write(images) 16 | -------------------------------------------------------------------------------- /Chapter11/copy_in_mfs.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | c.files_cp('/ipfs/QmY8zTocoVNDJWUr33nhksBiZ3hxugFPhb6qSzpE761bVN', '/46MB_cute_bear.mp4') 6 | 7 | print(c.files_ls('/')) 8 | -------------------------------------------------------------------------------- /Chapter11/crypto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package crypto; 4 | 5 | message CryptoCurrency { 6 | required string name = 1; 7 | optional int32 total_supply = 2; 8 | 9 | enum CryptoType { 10 | BITCOIN = 0; 11 | ERC20 = 1; 12 | PRIVATE = 2; 13 | } 14 | 15 | required CryptoType type = 3 [default = ERC20]; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter11/crypto_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: crypto.proto 3 | 4 | import sys 5 | _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import message as _message 8 | from google.protobuf import reflection as _reflection 9 | from google.protobuf import symbol_database as _symbol_database 10 | from google.protobuf import descriptor_pb2 11 | # @@protoc_insertion_point(imports) 12 | 13 | _sym_db = _symbol_database.Default() 14 | 15 | 16 | 17 | 18 | DESCRIPTOR = _descriptor.FileDescriptor( 19 | name='crypto.proto', 20 | package='crypto', 21 | serialized_pb=_b('\n\x0c\x63rypto.proto\x12\x06\x63rypto\"\x9f\x01\n\x0e\x43ryptoCurrency\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x14\n\x0ctotal_supply\x18\x02 \x01(\x05\x12\x36\n\x04type\x18\x03 \x02(\x0e\x32!.crypto.CryptoCurrency.CryptoType:\x05\x45RC20\"1\n\nCryptoType\x12\x0b\n\x07\x42ITCOIN\x10\x00\x12\t\n\x05\x45RC20\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02') 22 | ) 23 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 24 | 25 | 26 | 27 | _CRYPTOCURRENCY_CRYPTOTYPE = _descriptor.EnumDescriptor( 28 | name='CryptoType', 29 | full_name='crypto.CryptoCurrency.CryptoType', 30 | filename=None, 31 | file=DESCRIPTOR, 32 | values=[ 33 | _descriptor.EnumValueDescriptor( 34 | name='BITCOIN', index=0, number=0, 35 | options=None, 36 | type=None), 37 | _descriptor.EnumValueDescriptor( 38 | name='ERC20', index=1, number=1, 39 | options=None, 40 | type=None), 41 | _descriptor.EnumValueDescriptor( 42 | name='PRIVATE', index=2, number=2, 43 | options=None, 44 | type=None), 45 | ], 46 | containing_type=None, 47 | options=None, 48 | serialized_start=135, 49 | serialized_end=184, 50 | ) 51 | _sym_db.RegisterEnumDescriptor(_CRYPTOCURRENCY_CRYPTOTYPE) 52 | 53 | 54 | _CRYPTOCURRENCY = _descriptor.Descriptor( 55 | name='CryptoCurrency', 56 | full_name='crypto.CryptoCurrency', 57 | filename=None, 58 | file=DESCRIPTOR, 59 | containing_type=None, 60 | fields=[ 61 | _descriptor.FieldDescriptor( 62 | name='name', full_name='crypto.CryptoCurrency.name', index=0, 63 | number=1, type=9, cpp_type=9, label=2, 64 | has_default_value=False, default_value=_b("").decode('utf-8'), 65 | message_type=None, enum_type=None, containing_type=None, 66 | is_extension=False, extension_scope=None, 67 | options=None), 68 | _descriptor.FieldDescriptor( 69 | name='total_supply', full_name='crypto.CryptoCurrency.total_supply', index=1, 70 | number=2, type=5, cpp_type=1, label=1, 71 | has_default_value=False, default_value=0, 72 | message_type=None, enum_type=None, containing_type=None, 73 | is_extension=False, extension_scope=None, 74 | options=None), 75 | _descriptor.FieldDescriptor( 76 | name='type', full_name='crypto.CryptoCurrency.type', index=2, 77 | number=3, type=14, cpp_type=8, label=2, 78 | has_default_value=True, default_value=1, 79 | message_type=None, enum_type=None, containing_type=None, 80 | is_extension=False, extension_scope=None, 81 | options=None), 82 | ], 83 | extensions=[ 84 | ], 85 | nested_types=[], 86 | enum_types=[ 87 | _CRYPTOCURRENCY_CRYPTOTYPE, 88 | ], 89 | options=None, 90 | is_extendable=False, 91 | extension_ranges=[], 92 | oneofs=[ 93 | ], 94 | serialized_start=25, 95 | serialized_end=184, 96 | ) 97 | 98 | _CRYPTOCURRENCY.fields_by_name['type'].enum_type = _CRYPTOCURRENCY_CRYPTOTYPE 99 | _CRYPTOCURRENCY_CRYPTOTYPE.containing_type = _CRYPTOCURRENCY 100 | DESCRIPTOR.message_types_by_name['CryptoCurrency'] = _CRYPTOCURRENCY 101 | 102 | CryptoCurrency = _reflection.GeneratedProtocolMessageType('CryptoCurrency', (_message.Message,), dict( 103 | DESCRIPTOR = _CRYPTOCURRENCY, 104 | __module__ = 'crypto_pb2' 105 | # @@protoc_insertion_point(class_scope:crypto.CryptoCurrency) 106 | )) 107 | _sym_db.RegisterMessage(CryptoCurrency) 108 | 109 | 110 | # @@protoc_insertion_point(module_scope) 111 | -------------------------------------------------------------------------------- /Chapter11/download_a_directory_of_cute_cat_picture.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | directory = 'QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ' 6 | c.get(directory) 7 | -------------------------------------------------------------------------------- /Chapter11/download_cute_cat_picture.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | cute_cat_picture = 'QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg' 6 | c.get(cute_cat_picture) 7 | -------------------------------------------------------------------------------- /Chapter11/exploring_mfs.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | import io 3 | 4 | 5 | c = ipfsapi.connect() 6 | 7 | print("By default our MFS is empty.") 8 | print(c.files_ls('/')) # root is / just like Unix filesystem 9 | 10 | print("We can create a directory in our MFS.") 11 | c.files_mkdir('/classical_movies') 12 | 13 | print("We can create a file in our MFS.") 14 | c.files_write('/classical_movies/titanic', 15 | io.BytesIO(b"The ship crashed. The end."), 16 | create=True) 17 | 18 | print("We can copy a file in our MFS.") 19 | c.files_cp('/classical_movies/titanic', 20 | '/classical_movies/copy_of_titanic') 21 | 22 | print("We can read the file.") 23 | print(c.files_read('/classical_movies/titanic')) 24 | 25 | print("We can remove the file.") 26 | print(c.files_rm('/classical_movies/copy_of_titanic')) 27 | 28 | print("Now our MFS is not empty anymore.") 29 | print(c.files_ls('/')) 30 | print(c.files_ls('/classical_movies')) 31 | 32 | print("You can get the hash of a path in MFS.") 33 | print(c.files_stat('/classical_movies')) 34 | 35 | print("Then you can publish this hash into IPNS.") 36 | -------------------------------------------------------------------------------- /Chapter11/generate_another_key.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | print(c.key_list()) 6 | 7 | c.key_gen('another_key', 'rsa') 8 | 9 | print(c.key_list()) 10 | -------------------------------------------------------------------------------- /Chapter11/get_unicorn.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | result = c.cat('QmY7MiYeySnsed1Z3KxqDVYuM8pfiT5gGTqprNaNhUpZgR') 6 | print(result) 7 | -------------------------------------------------------------------------------- /Chapter11/get_unicorn_block.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | result = c.block_get('QmY7MiYeySnsed1Z3KxqDVYuM8pfiT5gGTqprNaNhUpZgR') 6 | print(result) 7 | -------------------------------------------------------------------------------- /Chapter11/hello.txt: -------------------------------------------------------------------------------- 1 | I am a good unicorn. 2 | -------------------------------------------------------------------------------- /Chapter11/horoscope1.txt: -------------------------------------------------------------------------------- 1 | You will meet the love of your life today! 2 | -------------------------------------------------------------------------------- /Chapter11/horoscope2.txt: -------------------------------------------------------------------------------- 1 | You need to be careful when going outside! 2 | -------------------------------------------------------------------------------- /Chapter11/image_from_blocks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter11/image_from_blocks.jpg -------------------------------------------------------------------------------- /Chapter11/keys_list.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | 3 | 4 | c = ipfsapi.connect() 5 | print(c.key_list()) 6 | -------------------------------------------------------------------------------- /Chapter11/list_blocks.py: -------------------------------------------------------------------------------- 1 | import ipfsapi 2 | import pprint 3 | 4 | 5 | c = ipfsapi.connect() 6 | 7 | blocks = c.ls('QmV5KPoHHqbq2NsALniERnaYjCJPi3UxLnpwdTkV1EbNZM') 8 | 9 | pp = pprint.PrettyPrinter(indent=2) 10 | pp.pprint(blocks) 11 | -------------------------------------------------------------------------------- /Chapter11/merkledag.proto: -------------------------------------------------------------------------------- 1 | package merkledag.pb; 2 | 3 | // An IPFS MerkleDAG Link 4 | message PBLink { 5 | 6 | // multihash of the target object 7 | optional bytes Hash = 1; 8 | 9 | // utf string name. should be unique per object 10 | optional string Name = 2; 11 | 12 | // cumulative size of target object 13 | optional uint64 Tsize = 3; 14 | } 15 | 16 | // An IPFS MerkleDAG Node 17 | message PBNode { 18 | 19 | // refs to other objects 20 | repeated PBLink Links = 2; 21 | 22 | // opaque user data 23 | optional bytes Data = 1; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter11/merkledag_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: merkledag.proto 3 | 4 | import sys 5 | _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import message as _message 8 | from google.protobuf import reflection as _reflection 9 | from google.protobuf import symbol_database as _symbol_database 10 | from google.protobuf import descriptor_pb2 11 | # @@protoc_insertion_point(imports) 12 | 13 | _sym_db = _symbol_database.Default() 14 | 15 | 16 | 17 | 18 | DESCRIPTOR = _descriptor.FileDescriptor( 19 | name='merkledag.proto', 20 | package='merkledag.pb', 21 | serialized_pb=_b('\n\x0fmerkledag.proto\x12\x0cmerkledag.pb\"3\n\x06PBLink\x12\x0c\n\x04Hash\x18\x01 \x01(\x0c\x12\x0c\n\x04Name\x18\x02 \x01(\t\x12\r\n\x05Tsize\x18\x03 \x01(\x04\";\n\x06PBNode\x12#\n\x05Links\x18\x02 \x03(\x0b\x32\x14.merkledag.pb.PBLink\x12\x0c\n\x04\x44\x61ta\x18\x01 \x01(\x0c') 22 | ) 23 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 24 | 25 | 26 | 27 | 28 | _PBLINK = _descriptor.Descriptor( 29 | name='PBLink', 30 | full_name='merkledag.pb.PBLink', 31 | filename=None, 32 | file=DESCRIPTOR, 33 | containing_type=None, 34 | fields=[ 35 | _descriptor.FieldDescriptor( 36 | name='Hash', full_name='merkledag.pb.PBLink.Hash', index=0, 37 | number=1, type=12, cpp_type=9, label=1, 38 | has_default_value=False, default_value=_b(""), 39 | message_type=None, enum_type=None, containing_type=None, 40 | is_extension=False, extension_scope=None, 41 | options=None), 42 | _descriptor.FieldDescriptor( 43 | name='Name', full_name='merkledag.pb.PBLink.Name', index=1, 44 | number=2, type=9, cpp_type=9, label=1, 45 | has_default_value=False, default_value=_b("").decode('utf-8'), 46 | message_type=None, enum_type=None, containing_type=None, 47 | is_extension=False, extension_scope=None, 48 | options=None), 49 | _descriptor.FieldDescriptor( 50 | name='Tsize', full_name='merkledag.pb.PBLink.Tsize', index=2, 51 | number=3, type=4, cpp_type=4, label=1, 52 | has_default_value=False, default_value=0, 53 | message_type=None, enum_type=None, containing_type=None, 54 | is_extension=False, extension_scope=None, 55 | options=None), 56 | ], 57 | extensions=[ 58 | ], 59 | nested_types=[], 60 | enum_types=[ 61 | ], 62 | options=None, 63 | is_extendable=False, 64 | extension_ranges=[], 65 | oneofs=[ 66 | ], 67 | serialized_start=33, 68 | serialized_end=84, 69 | ) 70 | 71 | 72 | _PBNODE = _descriptor.Descriptor( 73 | name='PBNode', 74 | full_name='merkledag.pb.PBNode', 75 | filename=None, 76 | file=DESCRIPTOR, 77 | containing_type=None, 78 | fields=[ 79 | _descriptor.FieldDescriptor( 80 | name='Links', full_name='merkledag.pb.PBNode.Links', index=0, 81 | number=2, type=11, cpp_type=10, label=3, 82 | has_default_value=False, default_value=[], 83 | message_type=None, enum_type=None, containing_type=None, 84 | is_extension=False, extension_scope=None, 85 | options=None), 86 | _descriptor.FieldDescriptor( 87 | name='Data', full_name='merkledag.pb.PBNode.Data', index=1, 88 | number=1, type=12, cpp_type=9, label=1, 89 | has_default_value=False, default_value=_b(""), 90 | message_type=None, enum_type=None, containing_type=None, 91 | is_extension=False, extension_scope=None, 92 | options=None), 93 | ], 94 | extensions=[ 95 | ], 96 | nested_types=[], 97 | enum_types=[ 98 | ], 99 | options=None, 100 | is_extendable=False, 101 | extension_ranges=[], 102 | oneofs=[ 103 | ], 104 | serialized_start=86, 105 | serialized_end=145, 106 | ) 107 | 108 | _PBNODE.fields_by_name['Links'].message_type = _PBLINK 109 | DESCRIPTOR.message_types_by_name['PBLink'] = _PBLINK 110 | DESCRIPTOR.message_types_by_name['PBNode'] = _PBNODE 111 | 112 | PBLink = _reflection.GeneratedProtocolMessageType('PBLink', (_message.Message,), dict( 113 | DESCRIPTOR = _PBLINK, 114 | __module__ = 'merkledag_pb2' 115 | # @@protoc_insertion_point(class_scope:merkledag.pb.PBLink) 116 | )) 117 | _sym_db.RegisterMessage(PBLink) 118 | 119 | PBNode = _reflection.GeneratedProtocolMessageType('PBNode', (_message.Message,), dict( 120 | DESCRIPTOR = _PBNODE, 121 | __module__ = 'merkledag_pb2' 122 | # @@protoc_insertion_point(class_scope:merkledag.pb.PBNode) 123 | )) 124 | _sym_db.RegisterMessage(PBNode) 125 | 126 | 127 | # @@protoc_insertion_point(module_scope) 128 | -------------------------------------------------------------------------------- /Chapter11/milada-vigerova-1284157-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter11/milada-vigerova-1284157-unsplash.jpg -------------------------------------------------------------------------------- /Chapter11/mysite/README.md: -------------------------------------------------------------------------------- 1 | This is Readme file. 2 | -------------------------------------------------------------------------------- /Chapter11/mysite/img/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Blockchain-for-Python-Developers/54a490f1b53b8c50cae48a93c509e04e05d05e9e/Chapter11/mysite/img/cat.jpg -------------------------------------------------------------------------------- /Chapter11/mysite/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 |