Published by O'Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
13 |
14 |
O'Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://oreilly.com/safari). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com.
15 |
16 |
17 |
Editor: Tim McGovern
18 |
19 |
20 |
21 |
22 |
23 |
24 |
The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Mastering Bitcoin, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.
25 |
26 |
While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. This book is not intended as legal or financial advice. Please consult a qualified professional if you require legal or financial] advice.
27 |
28 |
29 |
30 |
978-1-491-97194-0
31 |
32 |
[LSI]
33 |
34 |
35 |
--------------------------------------------------------------------------------
/code/auction_dapp/backend/test/2_deedrepository.js:
--------------------------------------------------------------------------------
1 | var DeedRepository = artifacts.require("./DeedRepository.sol");
2 | const fs = require('fs');
3 |
4 | contract('DeedRepository', async (accounts) => {
5 |
6 | let instance;
7 | let auctionContractAddress = "";
8 |
9 | beforeEach('setup contract for each test', async function () {
10 | instance = await DeedRepository.deployed();
11 | auctionContractAddress = fs.readFileSync("./test/output.address").toString()
12 | })
13 |
14 | it("It should create an deed repository with UANFT as symbol", async () => {
15 | let symbol = await instance.symbol();
16 | assert.equal(symbol.valueOf(), 'UANFT' , `Deedrepository symbol should be UANFT`);
17 | });
18 |
19 | it("It should register a deed with id: 123456789", async () => {
20 | await instance.registerDeed(accounts[0], 123456789);
21 | let ownerOfDeed = await instance.exists(123456789);
22 | assert.equal(ownerOfDeed.valueOf(), true , `Result should be true`);
23 | });
24 |
25 | it(`It should check owner of 123456789 who is ${accounts[0]}`, async () => {
26 | let ownerOfDeed = await instance.ownerOf(123456789);
27 | assert.equal(ownerOfDeed.valueOf(), accounts[0] , `Owner should be ${accounts[0]}`);
28 | });
29 |
30 | it(`It should check balance of ${accounts[0]}`, async () => {
31 | let balance = await instance.balanceOf(accounts[0]);
32 | assert.equal(balance.valueOf(), 1 , `balance ${balance} should be 1`);
33 | });
34 |
35 | it(`It should check total supply of the repository`, async () => {
36 | let supply = await instance.totalSupply();
37 | assert.equal(supply.valueOf(), 1 , `total supply: ${supply} should be 1`);
38 | });
39 |
40 | it(`It should approve transfer the ownership of 123456789 to the auctionRepository address`, async () => {
41 | await instance.approve(auctionContractAddress, 123456789);
42 | // console.log('this auction address:', auctionAddress, ' deedrepo instance addr', instance.address);
43 | let address = await instance.getApproved(123456789);
44 | assert.equal(address.valueOf(), auctionContractAddress, `${address} should be equal to ${auctionContractAddress}`);
45 | });
46 |
47 | it("It should transfer ownership of deed 123456789 to this contract", async () => {
48 | await instance.transferFrom( accounts[0] ,auctionContractAddress, 123456789, { from: accounts[0]});
49 | let newOwnerAddress = await instance.ownerOf(123456789);
50 | //let success = await instance.isApprovedOrOwner(auctionAddress, 123456789)
51 | assert.equal(newOwnerAddress.valueOf(), auctionContractAddress, `${newOwnerAddress} should be ${auctionContractAddress}`);
52 | });
53 |
54 |
55 | });
--------------------------------------------------------------------------------
/code/auction_dapp/frontend/src/models/DeedRepository.js:
--------------------------------------------------------------------------------
1 | import Config from '../config'
2 |
3 | export class DeedRepository {
4 |
5 | web3 = null
6 | account = ''
7 | contractInstance = null
8 | gas = 4476768
9 |
10 | constructor(){
11 | this.gas = Config.GAS_AMOUNT
12 | }
13 | setWeb3(web3) {
14 | this.web3 = web3
15 | this.contractInstance = this.web3.eth.contract(Config.DEEDREPOSITORY_ABI).at(Config.DEEDREPOSITORY_ADDRESS)
16 | }
17 |
18 | getWeb3() {
19 | return this.web3
20 | }
21 |
22 | setAccount(account){
23 | this.account = account
24 | }
25 |
26 | getCurrentBlock() {
27 | return new Promise((resolve, reject ) => {
28 | this.web3.eth.getBlockNumber((err, blocknumber) => {
29 | if(!err) resolve(blocknumber)
30 | reject(err)
31 | })
32 | })
33 | }
34 |
35 | // getAccounts() {
36 | // return new Promise((resolve, reject ) => {
37 | // this.web3.eth.getAccounts((err, accounts) => {
38 | // if(!err) resolve(accounts)
39 | // reject(err)
40 | // })
41 | // })
42 | // }
43 |
44 | async watchIfCreated(cb) {
45 | const currentBlock = await this.getCurrentBlock()
46 | const eventWatcher = this.contractInstance.DeedRegistered({}, {fromBlock: currentBlock - 1, toBlock: 'latest'})
47 | eventWatcher.watch(cb)
48 | }
49 |
50 | async watchIfDeedTransfered(cb) {
51 | const currentBlock = await this.getCurrentBlock()
52 | const eventWatcher = this.contractInstance.Transfer({}, {fromBlock: currentBlock - 1, toBlock: 'latest'})
53 | eventWatcher.watch(cb)
54 | }
55 |
56 | exists(deedId) {
57 | return new Promise(async (resolve, reject) => {
58 | this.contractInstance.exists(deedId, {from: this.account, gas: this.gas }, (err, transaction) => {
59 | if(!err) resolve(transaction)
60 | reject(err)
61 | })
62 | })
63 | }
64 |
65 | transferTo(to, deedId) {
66 | return new Promise(async (resolve, reject) => {
67 | this.contractInstance.transferFrom(this.account, to, deedId, {from: this.account, gas: this.gas }, (err, transaction) => {
68 | if(!err) resolve(transaction)
69 | reject(err)
70 | })
71 | })
72 |
73 | }
74 |
75 | create(deedId, deedURI) {
76 | console.log('contractinsatnce', this.contractInstance )
77 | return new Promise(async (resolve, reject) => {
78 | this.contractInstance.registerDeed(deedId, deedURI, {from: this.account, gas: this.gas }, (err, transaction) => {
79 | if(!err)
80 | resolve(transaction)
81 | else
82 | reject(err)
83 | })
84 | })
85 | }
86 | }
--------------------------------------------------------------------------------
/code/auction_dapp/README.md:
--------------------------------------------------------------------------------
1 | # Decentralized Auction Application on Ethereum
2 |
3 | This project aims to implement basic functionalities of an auction platform using Ethereum.
4 |
5 | ## Requirements
6 |
7 | 
8 |
9 | The application should be decentralized and utilize Ethereum's stack:
10 |
11 | 1. Smart contracts for business logic(auctions, bids, refund and transfer of ownership)
12 | 2. Swarm for data storage(image and metadata)
13 | 3. Whisper for a peer-to-peer messaging(chatrooms)
14 |
15 | ### Deed Repository
16 | Manage non-fungible tokens by implementing an asset/token/deed repository which holds unique asset/token/deed.
17 |
18 | #### ERC: Non-fungible Token Standard #721 (NFT)
19 | See following link:
20 | https://github.com/ethereum/eips/issues/721
21 |
22 | ### Auction Repository
23 |
24 | Auction repository MUST act as an auction house which does the following:
25 |
26 | - Holds asset/token/deed that is to be auctioned(ERC721 Ownership by smart contract)
27 | - Allows users bid on auctions
28 | - Keeps track of auctions/bids/ownership
29 | - Transfers ownership of asset/token/deed to winder
30 | - Transfers Funds to auction creator if auction is ended and there is at least one winner
31 | - Cancels auction and deal with refunds
32 | - UI to interact with the above functionality
33 |
34 | ### Front-end: Vuejs2.x + Vuetify
35 |
36 | The front-end is developed using a reactive UI framework with integration of Vuetify, a Google's Material Design implementation.
37 |
38 | ## Implementation/Data flow
39 |
40 | #### 1. Register an ERC721 Non-Fungible Token with the AuctionDaap Deed Repository
41 |
42 | The idea of a Deed Repository is used across this project to hold any NFT with metadata attached to. A token/deed is registered by giving a unique ID and attaching metadata(TokenURI). The metadata is what makes each token important or valuable.
43 |
44 | #### 2. Transfer Ownership of the NFT to AuctionRepository(Auction house)
45 |
46 | The Auction house needs to verify that a NFT is owned by the auction creator, therefore before the auction is created, the owner should transfer the ownership of the NFT to the AuctionRepository smart contract address.
47 |
48 | #### 3. Create Auction for NFT
49 |
50 | Creating the auction is a simple process of entering auction details such as name, strarting price, expirty date etc. The important part is to have the reference between the deed and the auction.
51 |
52 | #### 4. Bid on Auction
53 |
54 | Anyone can bid on an auction except the owner of the auction. Biding means that previous bidders are refunded and new bid is placed. Bid requirements are as follow:
55 | 1. Auction not expired
56 | 2. Bidder is not auction owner
57 | 3. Bid amount is greator than current bid or starting price(if no bid)
58 |
59 | #### 5. Refunds
60 |
61 | If an auction is canceled, the Auction Repository MUST return the ownership of the asset/token/deed back to the auction creator and refund bidders if any.
62 |
63 | #### 5. Bidder Win Auction
64 |
65 | If there is an auction winner, the asset/token/deed is transfered to the bidder and the bid amount is sent to the auction creator.
66 |
67 |
--------------------------------------------------------------------------------
/code/auction_dapp/backend/test/1_auctionrepository.js:
--------------------------------------------------------------------------------
1 | var AuctionRepository = artifacts.require("./AuctionRepository.sol");
2 | //var DeedRepository = artifacts.require("./DeedRepository.sol");
3 | const fs = require('fs');
4 |
5 | contract('AuctionRepository', async (accounts) => {
6 |
7 | it("It should check if the auction repository is initialized", async () => {
8 | let instance = await AuctionRepository.deployed();
9 | fs.writeFileSync('./test/output.address', instance.address);
10 | let auctionLength = await instance.getAuctionsCount();
11 | assert.equal(auctionLength.valueOf(), 0, `${auctionLength} auctions instead of 0`);
12 | });
13 |
14 | // it("It should approve transfer of ownership of the 123456789 token", async () => {
15 | // //let instance = await DeedRepository.deployed();
16 | // //let totalSupply = await instance.totalSupply();
17 |
18 | // let auctionInstance = await AuctionRepository.deployed();
19 | // let auctionAddress = auctionInstance.address;
20 | // await instance.approve(auctionAddress, 123456789);
21 |
22 | // // console.log('this auction address:', auctionAddress, ' deedrepo instance addr', instance.address);
23 | // let address = await instance.getApproved(123456789);
24 | // assert.equal(address.valueOf(), auctionAddress, `${address} should be equal to ${auctionAddress}`);
25 | // });
26 |
27 | // it("It should transfer ownership of deed to this contract", async () => {
28 | // let instance = await DeedRepository.deployed();
29 | // let auctionInstance = await AuctionRepository.deployed();
30 | // let auctionAddress = auctionInstance.address;
31 | // await instance.transferFrom( accounts[0] ,auctionAddress, 123456789, { from: accounts[0]});
32 | // let newOwnerAddress = await instance.ownerOf(123456789);
33 | // //let success = await instance.isApprovedOrOwner(auctionAddress, 123456789)
34 | // assert.equal(newOwnerAddress.valueOf(), auctionAddress, `${newOwnerAddress} should be ${auctionAddress}`);
35 | // });
36 |
37 | // it(`It should create an auction under ${accounts[0]} account`, async () => {
38 | // let instance = await AuctionRepository.deployed();
39 | // await instance.createAuction(accounts[0], 123456789, "MYNFT", "meta://", 10, 1533772800, accounts[0] );
40 | // let auctionCount = await instance.getAuctionsCountOfOwner(accounts[0]);
41 | // assert.equal(auctionCount.valueOf(), 1, `auctions of ${accounts[0]} should be 1`);
42 | // });
43 |
44 | // it(`It should bid on the last auction`, async () => {
45 | // let instance = await AuctionRepository.deployed();
46 | // await instance.bidOnAuction(0, 1000);
47 | // let bidsCount = await instance.getBidsCount(0);
48 | // assert.equal(bidsCount.valueOf(), 1, `bids should be 1`);
49 | // });
50 |
51 | // it(`It should bid on the last auction`, async () => {
52 | // let instance = await AuctionRepository.deployed();
53 | // await instance.bidOnAuction(0, 10000 );
54 | // let bidsCount = await instance.getBidsCount(0);
55 | // assert.equal(bidsCount.valueOf(), 2, `bids should be 1`);
56 | // });
57 |
58 |
59 | });
--------------------------------------------------------------------------------
/code/auction_dapp/frontend/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App'
3 | import Config from './config'
4 | import router from './router'
5 | import Vuetify from 'vuetify'
6 | import VueResource from 'vue-resource'
7 | import { ChatRoom } from './models/ChatRoom'
8 | import { DeedRepository } from './models/DeedRepository'
9 | import { AuctionRepository } from './models/AuctionRepository'
10 |
11 | // rename to avoid conflict between metamask
12 | // will be used for whisper v5/6
13 | var Web3_1 = require('web3')
14 |
15 | Vue.use(VueResource)
16 | Vue.use(Vuetify)
17 | Vue.config.productionTip = false
18 |
19 | // state management
20 | var store = {
21 | debug: true,
22 | state: {
23 | // metamask state variable
24 | metamask: {
25 | web3DefaultAccount: '',
26 | metamaskInstalled: false,
27 | networkId: '',
28 | },
29 |
30 | // local web3 instance(not metamask)
31 | web3 : null,
32 |
33 | },
34 | networkReady() {
35 | return this.getNetworkId() != '' && this.getMetamaskInstalled() && this.getWeb3DefaultAccount() != ''
36 | },
37 | setNetworkId(networkId) {
38 | this.state.metamask.networkId = networkId
39 | },
40 | getNetworkId() {
41 | return this.state.metamask.networkId
42 | },
43 |
44 | setWeb3DefaultAccount(account) {
45 | this.state.metamask.web3DefaultAccount = account
46 | },
47 | getWeb3DefaultAccount() {
48 | return this.state.metamask.web3DefaultAccount
49 | },
50 |
51 | setMetamaskInstalled(){
52 | this.state.metamask.metamaskInstalled = true
53 | },
54 | getMetamaskInstalled(){
55 | return this.state.metamask.metamaskInstalled
56 | },
57 |
58 | getRandomInt(min, max) {
59 | return Math.floor(Math.random() * (max - min + 1)) + min
60 | }
61 | }
62 |
63 |
64 | Vue.mixin({
65 | created: function () {
66 | // Inject the models to components
67 | this.$chatroomInstance = new ChatRoom()
68 | this.$deedRepoInstance = new DeedRepository()
69 | this.$auctionRepoInstance = new AuctionRepository()
70 |
71 | this.$chatroomInstance.setWeb3(new Web3_1(Config.SHH_ENDPOINT))
72 |
73 | // one instance of web3 available to all components
74 | if (typeof web3 !== 'undefined') {
75 | web3 = new Web3(web3.currentProvider)
76 | this.$auctionRepoInstance.setWeb3(web3)
77 | this.$deedRepoInstance.setWeb3(web3)
78 |
79 | store.setMetamaskInstalled()
80 | web3.version.getNetwork((err, netId) => {
81 | store.setNetworkId(netId)
82 | })
83 | // pull accounts every 2 seconds
84 | setInterval(() => {
85 | web3.eth.getAccounts((err, data) => {
86 | if(data.length > 0) store.setWeb3DefaultAccount(data[0])
87 | })
88 | }, 2000)
89 | }
90 | // inject config to components
91 | this.$config = Config
92 | }
93 | })
94 |
95 |
96 | new Vue({
97 | el: '#app',
98 | data: {
99 | globalState: store,
100 | },
101 | router,
102 | template: '',
103 | components: { App },
104 | mounted() {
105 |
106 | }
107 | })
108 |
--------------------------------------------------------------------------------
/author_bio.html:
--------------------------------------------------------------------------------
1 |
2 |
About the Authors
3 |
Andreas M. Antonopoulos is a noted technologist and serial entrepreneur who has become one of the most well-known and well-respected figures in Bitcoin. As an engaging public speaker, teacher, and writer, Andreas makes complex subjects accessible and easy to understand. As an advisor, he helps startups recognize, evaluate, and navigate security and business risks.
4 |
5 |
Andreas grew up with the internet, starting his first company, an early BBS and proto-ISP, as a teenager in his home in Greece. He earned degrees in computer science, data communications, and distributed systems from University College London (UCL)—recently ranked among the world’s top 10 universities. After moving to the United States, Andreas cofounded and managed a successful technology research company, and in that role advised dozens of Fortune 500 company executives on networking, security, data centers, and cloud computing. More than 200 of his articles on security, cloud computing, and data centers have been published in print and syndicated worldwide. He holds two patents in networking and security.
6 |
7 |
In 1990, Andreas started teaching various IT topics in private, professional, and academic environments. He honed his speaking skills in front of audiences ranging in size from five executives in a boardroom to thousands of people in large conferences. With more than 400 speaking engagements under his belt he is considered a world-class and charismatic public speaker and teacher. In 2014, he was appointed as a teaching fellow with the University of Nicosia, the first university in the world to offer a masters degree in digital currency. In this role, he helped develop the curriculum and cotaught the Introduction to Digital Currencies course, offered as a massive open online course (MOOC) through the university.
8 |
9 |
As a Bitcoin entrepreneur, Andreas has founded a number of Bitcoin businesses and launched several community open source projects. He serves as an advisor to several Bitcoin and cryptocurrency companies. He is a widely published author of articles and blog posts on Bitcoin, a permanent host on the popular Let’s Talk Bitcoin podcast, and a frequent speaker at technology and security conferences worldwide.
10 |
11 |
12 |
Gavin Wood:
13 | When Gavin first read about Bitcoin in 2011, he was largely uninterested, focusing too much on the currency aspect rather than the technology. However, when he revisited it in early 2013, he began to realise new possibilities opening up between the fields of ITC and game theory, and the inevitable social change to which this would lead. A mutual friend made the introduction to Vitalik Buterin (Ethereum Founder) in late 2014 and Ethereum has dominated Gavin Wood's life since.Gavin coded the first functional implementation of Ethereum, devised the Solidity contract language and wrote the Yellow Paper, the first formal specification of any blockchain protocol and one of the key ways Ethereum distinguishes itself from other blockchain-based systems. Prior to Ethereum, Gavin earned a masters degree and doctorate in computer science. He consulted for Microsoft Research on technical aspects of embedded domain-specific languages, and was involved in several startups in the areas of realtime semantic extraction and presentation for music, visual meta-programming systems and automated legal text analysis.
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/code/web3js/web3js_demo/web3-contract-basic-interaction-async-await.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * @author Francisco Javier Rojas García
5 | */
6 |
7 | console.log('Mastering Ethereum - web3.js basic interactions using async/await')
8 | console.log('Author: Francisco Javier Rojas García - fjrojasgarcia@gmail.com')
9 |
10 | var Web3 = require('web3');
11 | var fs = require('fs')
12 |
13 | // Prepare your Infura host url
14 | var infura_host = "https://kovan.infura.io"
15 |
16 | // Instantiate web3 provider
17 | var web3 = new Web3(infura_host);
18 |
19 | // Let's do some basic interactions at web3 level
20 | async function basicInterations() {
21 | // Let's see the Protocol Version
22 | var protocolVersion = await web3.eth.getProtocolVersion();
23 | console.log(`Protocol Version: ${protocolVersion}`);
24 |
25 | // Now I'm curious about the current gas price
26 | var gasPrice = await web3.eth.getGasPrice();
27 | console.log(`Gas Price: ${gasPrice}`);
28 |
29 | // And, Whats the last mined block in my chain?
30 | var blockNumber = await web3.eth.getBlockNumber();
31 | console.log(`Block Number: ${blockNumber}`);
32 |
33 | // Now let's dive into some basics actions with a contract
34 | // We will use the contract at;
35 | // https://kovan.etherscan.io/address/0xd0a1e359811322d97991e03f863a0c30c2cf029c#code
36 |
37 | // First things first, let's initialize our contract address
38 | var our_contract_address = "0xd0A1E359811322d97991E03f863a0C30C2cF029C";
39 |
40 | // Let's see its balance
41 | var balance = await web3.eth.getBalance(our_contract_address);
42 | console.log(`Balance of ${our_contract_address}: ${balance}`);
43 |
44 | // Now let's see its byte code
45 | var code = await web3.eth.getCode(our_contract_address);
46 | console.log("Contract code: ----------------------------------------------\n");
47 | console.log(code);
48 | console.log("-------------------------------------------------------------\n");
49 |
50 | // Let's initialize our contract url in Etherescan for Kovan chain
51 | var etherescan_url = `http://kovan.etherscan.io/api?module=contract&action=getabi&address=${our_contract_address}`
52 | console.log(etherescan_url);
53 |
54 | var client = require('node-rest-client-promise').Client();
55 |
56 | var etherescan_response = await client.getPromise(etherescan_url)
57 |
58 | // Leave this two lines for future object analysis
59 | //const util = require('util')
60 | //console.log(util.inspect(etherescan_response, false, null))
61 |
62 | // We get here our contract ABI
63 | our_contract_abi = JSON.parse(etherescan_response.data.result);
64 |
65 | // Let's instantiate our contract object
66 | var our_contract = await new web3.eth.Contract(our_contract_abi, our_contract_address);
67 |
68 | // Let's see our contract address
69 | console.log(`Our Contract address: ${our_contract._address}`);
70 |
71 | // or in this other way
72 | console.log(`Our Contract address in other way: ${our_contract.options.address}`);
73 |
74 | // Now our contract abi
75 | console.log("Our contract abi: " + JSON.stringify(our_contract.options.jsonInterface));
76 |
77 | // This is turning more interesting, let's see what's going with our contract methods
78 | // Now let's see our contract total supply
79 | var totalSupply = await our_contract.methods.totalSupply().call();
80 | console.log(`Total Supply of Our Contract address ${our_contract._address}: ${totalSupply}`);
81 |
82 | // Now let's see our contract public variable name
83 | var name = await our_contract.methods.name().call();
84 | console.log(`Public variable name of our Contract address ${our_contract._address}: ${name}`);
85 |
86 | // Now let's see our contract public variable symbol
87 | var symbol = await our_contract.methods.symbol().call();
88 | console.log(`Public variable symbol of our Contract address ${our_contract._address}: ${symbol}`);
89 | }
90 |
91 | // Let's interact with a node
92 | basicInterations();
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ____________________**Watch a video tutorial on how to contribute ---->**[](https://www.youtube.com/watch?v=IBYHohWm_5w)
2 |
3 |
4 | Chat: [](https://gitter.im/ethereumbook/Lobby)
5 |
6 | Project Management: [](https://waffle.io/ethereumbook/ethereumbook)
7 |
8 |
9 | # Mastering Ethereum
10 |
11 | Mastering Ethereum is a book for developers, offering a guide to the operation and use of the Ethereum, Ethereum Classic, RootStock (RSK) and other compatible EVM-based open blockchains.
12 |
13 | This repository contains the draft of the book, currently in progress, scheduled for publication in Q4'2018 by O'Reilly Media. The publication date has been delayed, unfortunately, due to some personal issues. Expect to see content developed and pushed here in Q1 and Q2 2018.
14 |
15 | # Contents
16 |
17 | The current status of the book is **CONTENT FREEZE - TECH REVIEW**. Only errors, fixes and typos will be accepted. Any new content submissions will be delayed for the second edition, which goes into production in late 2019 or early 2020.
18 |
19 |
20 | Here's what is available now:
21 |
22 | | Section | Progress | Content Complete |
23 | |-------|------|:------:|
24 | | [Preface](preface.asciidoc) | #### ||
25 | | [Glossary](glossary.asciidoc) | ######## | :heavy_check_mark: |
26 | | [What is Ethereum](what-is.asciidoc) | ######### | :heavy_check_mark: |
27 | | [Introduction](intro.asciidoc) | ############# | :heavy_check_mark: |
28 | | [Ethereum Clients](clients.asciidoc) | ########## | :heavy_check_mark: |
29 | | [Ethereum Testnets](ethereum-testnets.asciidoc) | #### ||
30 | | [Keys and Addresses](keys-addresses.asciidoc) | ############# | :heavy_check_mark: |
31 | | [Wallets](wallets.asciidoc) | ########### | :heavy_check_mark: |
32 | | [Transactions](transactions.asciidoc) | ############### | :heavy_check_mark: |
33 | | [Smart Contracts](smart-contracts.asciidoc) | ########################## | :heavy_check_mark: |
34 | | [Dev Tools and Frameworks](dev-tools.asciidoc) | ########## | :heavy_check_mark: |
35 | | [Tokens](tokens.asciidoc) | ################### | :heavy_check_mark: |
36 | | [DApps](dapps.asciidoc) | #### ||
37 | | [Oracles](oracles.asciidoc) | ####### | :heavy_check_mark: |
38 | | [Accounting & Gas](gas.asciidoc) | #### | :heavy_check_mark: |
39 | | [EVM](evm.asciidoc) | ####### | :heavy_check_mark: |
40 | | [Consensus](consensus.asciidoc) | ####### | :heavy_check_mark: |
41 | | [Vyper](vyper.asciidoc) | ##### | :heavy_check_mark: |
42 | | [DevP2P Protocol](devp2p-protocol.asciidoc) | ### | :heavy_check_mark: |
43 | | [Ethereum Standards (EIPs/ERCs)](standards-eip-erc.asciidoc) | #### | :heavy_check_mark: |
44 | | [Forks History (DAO/ETC)](forks-history.asciidoc) | ###### | :heavy_check_mark: |
45 |
46 |
47 | # Contributing, reviewing and commenting
48 |
49 | This book is developed collaboratively and openly, here on Github. We accept comments, contributions and corrections from all.
50 |
51 | To chat with the authors and editors:
52 |
53 |
54 | [](https://gitter.im/ethereumbook/Lobby)
55 |
56 | To contribute, see the detailed [Contributing Guide](CONTRIBUTING.md).
57 |
58 | # Source & License
59 |
60 | The book's source code, found in this repository, is kept synchronized with the print and ebook editions.
61 |
62 | The [develop branch](https://github.com/ethereumbook/ethereumbook/tree/develop), containing the most recent changes you see here is the in-progress drafting of Mastering Ethereum.
63 |
64 | Mastering Ethereum by The Ethereum Book LLC and Gavin Wood is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
65 |
66 | It is expected that the book will be released under a more permissive CC-BY-SA license within a year of publication.
67 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Guide to Contributing
2 |
3 | This book is developed collaboratively and openly, here on Github. We accept comments, contributions and corrections from all.
4 |
5 | ## Gitter Chat
6 |
7 | To chat with the authors and editors:
8 |
9 | [](https://gitter.im/ethereumbook/Lobby)
10 |
11 | ## License and attribution
12 |
13 | All contributions must be properly licensed and attributed. If you are contributing your own original work, then you are offering it under a CC-BY license (Creative Commons Attribution). You are responsible for adding your own name or pseudonym in the Acknowledgments section in the [Preface](preface.asciidoc), as attribution for your contribution.
14 |
15 | If you are sourcing a contribution from somewhere else, it must carry a compatible license. The book will initially be released under a CC-BY-NC-ND license which means that contributions must be licensed under open licenses such as MIT, CC0, CC-BY, etc. You need to indicate the original source and original license, by including an asciidoc markup comment above your contribution, like this:
16 |
17 | ```
18 | ////
19 | Source: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
20 | License: CC0
21 | Added by: @aantonop
22 | ////
23 | ```
24 |
25 | ## Contributing with a Pull Request
26 |
27 | The best way to contribute to this book is by making a pull request:
28 |
29 | 1. Login with your Github account or create one now
30 | 2. [Fork](https://github.com/ethereumbook/ethereumbook#fork-destination-box) the ethereumbook repository. Work on your fork.
31 | 3. Create a new branch on which to make your change, e.g.
32 | `git checkout -b my_code_contribution`, or make the change on the `develop` branch.
33 | 4. Please do one pull request PER asciidoc file, to avoid large merges. Edit the asciidoc file where you want to make a change or create a new asciidoc file in the `contrib` directory if you're not sure where your contribution might fit.
34 | 5. Edit `preface.asciidoc` and add your own name to the list of contributors under the Acknowledgment section. Use your name, or a github ID, or a pseudonym.
35 | 6. Commit your change. Include a commit message describing the correction.
36 | 7. Submit a pull request against the ethereumbook repository.
37 |
38 | Here's a video tutorial to help you make your first pull request:
39 |
40 | [](https://www.youtube.com/watch?v=IBYHohWm_5w)
41 |
42 | ## Contributing with an Issue
43 |
44 | If you find a mistake and you're not sure how to fix it, or you don't know how to do a pull request, then you can file an Issue. Filing an Issue will help us see the problem and fix it.
45 |
46 | Create a [new Issue](https://github.com/ethereumbook/ethereumbook/issues/new) now!
47 |
48 | ## Heading styles normalization across the book
49 |
50 | Adjust heading style in each section as follows:
51 |
52 | 1. Only the chapter/section should be level 2, everything else should be level 3 and below (level 1 is the book title itself). Each asciidoc file should start with a "==" heading.
53 | 2. All lower case, except for first letter, proper nouns and acronyms. "What is this thing?", "What is the Ethereum sprocket?" "Who created the Ethereum Name Service (ENS)"
54 | 3. Acronyms are spelled out, capitalized, with the acronym in parentheses. Once you have spelled out an acronym in one heading, we can keep it as an acronym in subsequent headings.
55 | 4. No period at the end. Question mark if it is a question (generally avoid question headings, unless really appropriate)
56 | 5. Should include a unique anchor (see #279), all lower case, underscore separated.
57 | 6. Headings should be followed by a blank line.
58 | 7. Heading should be followed by a paragraph of text, not a lower-level heading without any text. If you find one like this, add a TODO comment (line of 4 slashes "////", line with "TODO: add paragraph", line of 4 slashes)
59 |
60 | ## Line endings
61 |
62 | All submission should use Unix-like line endings: LF (not CR, not CR/LF). All the postprocessing is done on Unix-like systems. Incorrect line endings, or changes to line endings cause confusion for the diff tools and make the whole file look like it has changed.
63 |
64 | If you are unsure or your OS makes things difficult, consider using a developer's text editor such as Atom.
65 |
66 | ## Thanks
67 |
68 | We are very grateful for the support of the entire Ethereum community. With your help, this will be a great book that can help thousands of developers get started and eventually "master" Ethereum. Thank you!
69 |
--------------------------------------------------------------------------------
/contrib/scaling.asciidoc:
--------------------------------------------------------------------------------
1 | == Scaling
2 |
3 | One the most notable problems public blockchains face is scaling. According to Wikipedia, the definition of scaling in general can be "a computer's or network's ability to function as the number of users increases.". When talking about a blockchain, usage of the system is expressed in transactions. Based on that, we can define scalability in a blockchain as the ability of the network to function as the number of transactions increases. A popular way to measure scalability of a blockchain is measuring how much transactions per second (TPS) it can process.
4 |
5 | Ethereum itself can support around 15 state updates (aka. transactions) per second, compared to around 500 transactions per second PayPal can support
6 | or the millions state updates (tweets, comment, likes etc.) Twitter supports we can clearly see the problem, Ethereum can not support a massive adoption of users
7 | without solving this problem. A great example of this would be the infamous Crypto Kitties flu of December 2017, it showed us exactly what a
8 | small pick in the usage of Ethereum can do to the network, transactions were taking hours to days and the fees were about 40 Gwei -
9 | more than 10 times higher than the typical fee.
10 |
11 | === "The Blockchain Trillema"
12 |
13 | The reason for these scalability issues can be explained using what's called "The Blockchain Trillema".
14 | This is a trillema where (without a decent solution) a blockchain can support only 2 edges of the triangle and needs to compromise on the on third one.
15 | The three edges are:
16 |
17 | * Scalability
18 | * Decentralization
19 | * Security
20 |
21 | We can look at what each combination of 2 out of the 3 may look like.
22 |
23 | Scalability combined with Security - This could be a private blockchain, since the consensus needs to be achieved is only between a small cluster of trusted nodes (or maybe only one)
24 | there is no need for many security features public blockchains need and the communication between a few nodes is much faster than between a big decentralized network.
25 |
26 | Scalability combined with Decentralization - A great example for that could be a public blockchain such as Bitcoin or Ethereum, but with neither 0 block confirmations
27 | this may allow instant transactions with no fees but it is extremely insecure to the point it is just not useful for almost no use cases.
28 |
29 | Decentralization and Security - this is certainly where most public blockchains including Bitcoin and Ethereum are at, they are decentralized and secure
30 | but as said before, they do not support strong scaling solutions currently.
31 |
32 | The problem with this Trillema is you can't completely win it, you just can't support very high TPS, have huge open network of nodes and be secure enough.
33 |
34 | With that in mind, we can start exploring the different approaches of scaling the public blockchain without decreasing decentralization nor security
35 | it is important to understand, since it is not possible to completely satisfy all the 3 at the same time most solutions aim to get to some point in the middle
36 | where they have decent security, decentralization and scalability.
37 |
38 | == Attempts at scaling
39 |
40 | === Casper - Proof of Stake for Ethereum
41 | Proof of Stake is a relativly new type of consensus algorithm aims to improve/ replace the current Proof of Work consensus. The idea of Proof of Work consensus algoritm, in its simplest form, is to allow reaching consensus based on a 1 CPU 1 vote. Proof of Stake introduces a new voting power distribution idea in a 1 coin 1 vote basis.
42 | Proof of Stake was designed to provide blockchain with finality, strengthen the economical security, reduce centralization risks and make the protocol better for the environment by removing the Proof of Work energy waste. Nevertheless, you should keep in mind this are the theoretically intended outcomes of the Proof of Stake consensus algorithm and there are potential drawbacks Proof of Stake can have.
43 |
44 | Ethereum has decided to shift its consensus algorithm from Proof of Work to Proof of stake. The new Proof of Stake algoritm in Ethereum is called Casper - The Friendly GHOST. It was decided that the transition to Proof of Stake will be done in 2 phases. The first one is a hyberid Proof of Work - Proof of Stake algorithm called Casper the Friendly Finality Gadget (FFG) which aims to provide finality and implicitly reduce energy waste. The second implementation is called Casper Correct By Construction (CBC), this is a Proof of Stake only algorithm and will complete the Ethereum transition from Proof of Work to Proof of Stake.
45 |
46 | Casper the Fiendly Finality Gadget (FFG)
47 |
48 |
49 | Casper Correct by Construction (CBC)
50 |
51 | Sharding
52 |
53 | Plasma
54 |
55 | Raiden
56 |
57 | Counterfactual State Channels
58 |
59 | Truebit
60 |
61 | Loom Network
62 |
--------------------------------------------------------------------------------
/web3-contract-basic-interaction-async-await.asciidoc:
--------------------------------------------------------------------------------
1 | == web3.js contract basic interaction (async/await) as if they were synchronous functions
2 |
3 | === Description
4 | This script is for educational use and is based on web3@1.0.0-beta.29 web3.js version.
5 |
6 | It should be see as an introduction to web3.js.
7 |
8 | The web3.js library is a collection of modules which contain specific functionality for the Ethereum ecosystem.
9 |
10 | The web3.js object is an umbrella package to house all Ethereum related modules.
11 |
12 | This is the Ethereum compatible JavaScript API which implements the Generic JSON RPC spec.
13 |
14 | It run in a blocked (async/await) mode to move the reader away from the hell of the Promises as long as their version of nodejs or javascript allows it.
15 |
16 | The most remarkable thing about this script is that you don’t need to run your own local node to use it, because it use the https://infura.io[Infura services].
17 |
18 | === Prepare the environment
19 | To see this script in action you should follow this simple steps.
20 |
21 | ==== Check you have a valid npm version
22 | ----
23 | $ npm -v
24 | 5.6.0
25 | ----
26 |
27 | ==== If you don't have already done, initialize your package
28 | ----
29 | $ npm init
30 | ----
31 |
32 | ==== Install basic dependences
33 | ----
34 | npm i web3
35 | npm i node-rest-client-promise
36 | ----
37 |
38 | This will update your package.json cofiguracion file with your new dependences.
39 |
40 | ==== Node.js script execution
41 |
42 | Execution example;
43 | ----
44 | code/web3js/./web3-contract-basic-interaction-async-await.js
45 | ----
46 |
47 | == What the hell this script do?
48 | This script try to introduce to the basic use of web3.js using async/await (less Code), as if they were synchronous functions that return values directly instead of promises.
49 |
50 | === web3 provider
51 | We use web3.js Web3 object to obtain a basic web3 provider.
52 |
53 | ----
54 | var web3 = new Web3(infura_host);
55 | ----
56 |
57 | === Let's do some basic interactions at web3 level
58 | Let's get the Protocol Version.
59 |
60 | ----
61 | var protocolVersion = await web3.eth.getProtocolVersion();
62 | ----
63 |
64 | Now I'm curious about the current gas price.
65 |
66 | ----
67 | var gasPrice = await web3.eth.getGasPrice();
68 | ----
69 |
70 | And, Whats the last mined block in my chain?
71 |
72 | ----
73 | var blockNumber = await web3.eth.getBlockNumber();
74 | ----
75 |
76 | === Now let's dive into some basics actions with a contract
77 | We will use the contract at;
78 | https://kovan.etherscan.io/address/0xd0a1e359811322d97991e03f863a0c30c2cf029c#code
79 |
80 | First things first, let's initialize our contract address.
81 |
82 | ----
83 | var our_contract_address = "0xd0A1E359811322d97991E03f863a0C30C2cF029C";
84 | ----
85 |
86 | Let's get its balance.
87 |
88 | ----
89 | var balance = await web3.eth.getBalance(our_contract_address);
90 | ----
91 |
92 | Now let's get its byte code.
93 |
94 | ----
95 | var code = await web3.eth.getCode(our_contract_address);
96 | ----
97 |
98 | === Now we are going to deal with the contract
99 | We prepare our environment to interact with the Etherescan explorer API.
100 |
101 | Let's initialize our contract url in the Etherescan explorer API for the Kovan chain.
102 |
103 | ----
104 | var etherescan_url = `http://kovan.etherscan.io/api?module=contract&action=getabi&address=${our_contract_address}`
105 | ----
106 |
107 | And now get a rest client to operate with.
108 |
109 | ----
110 | var client = require('node-rest-client-promise').Client();
111 | ----
112 |
113 | Let's get the client response.
114 |
115 | ----
116 | var etherescan_response = await client.getPromise(etherescan_url)
117 | ----
118 |
119 | Now we get here our contract ABI from the client response (from the Etherescan explorer).
120 |
121 | ----
122 | our_contract_abi = JSON.parse(etherescan_response.data.result);
123 | ----
124 |
125 | Let's instantiate our contract object
126 |
127 | ----
128 | var our_contract = await new web3.eth.Contract(our_contract_abi, our_contract_address);
129 | ----
130 |
131 | Let's see our contract address.
132 | ----
133 | console.log(`Our Contract address: ${our_contract._address}`);
134 | ----
135 |
136 | or in this other way.
137 | ----
138 | console.log(`Our Contract address in other way: ${our_contract.options.address}`);
139 | ----
140 |
141 | Now our contract abi.
142 | ----
143 | console.log("Our contract abi: " + JSON.stringify(our_contract.options.jsonInterface));
144 | ----
145 |
146 | === This is turning more interesting, let's see what's going on with our contract
147 | Now let's get our contract total supply.
148 |
149 | ----
150 | var totalSupply = await our_contract.methods.totalSupply().call();
151 | ----
152 |
153 | Now let's get our contract public variable name.
154 |
155 | ----
156 | var name = await our_contract.methods.name().call();
157 | ----
158 |
159 | Now let's get our contract public variable symbol.
160 |
161 | ----
162 | var symbol = await our_contract.methods.symbol().call();
163 | ----
164 |
--------------------------------------------------------------------------------
/code/misc/example_keys.txt:
--------------------------------------------------------------------------------
1 | $ echo -n "Mastering Ethereum" | keccak-256sum
2 | F8F8A2F43C8376CCB0871305060D7B27B0554D2CC72BCCF41B2705608452F315 -
3 |
4 | Private Key
5 | f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315
6 |
7 | Public Key
8 | 046e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0
9 |
10 | Prefix: 04
11 | X:
12 | 6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b
13 | Y:
14 | 83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0
15 |
16 | ETH Address (mixed cap)
17 | 0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
18 |
19 | -------
20 |
21 | MetaMask seed
22 | piano tower spell inhale drama inside else quarter quality velvet small fit
23 |
24 | Available Accounts
25 | ==================
26 | (0) 0x9e713963a92c02317a681b9bb3065a8249de124f
27 | (1) 0xb0920c523d582040f2bcb1bd7fb1c7c1ecebdb34
28 | (2) 0xa49b21493176e73d5d24368cde4c1e6e5380e83a
29 | (3) 0xadb5191bc45ee6b6992a05a7cab778727700d469
30 | (4) 0x47121eacb0b0a61ff2699d702f7773b521ff8bea
31 | (5) 0x3a6e24b67bf25f5c1b988f068300e390ff398e0d
32 | (6) 0x64030e9b656b1fbdc568547dce3a8e7a6d75e4f6
33 | (7) 0x97656373117b650900d3732d8a3e7248afd10d63
34 | (8) 0x6e135145a1ea7cd97fb50cb2cc209766afde5f6b
35 | (9) 0xda9f13c519e5f34ebcae3d81c23660267861f7c0
36 |
37 | Private Keys
38 | ==================
39 | (0) 91c8360c4cb4b5fac45513a7213f31d4e4a7bfcb4630e9fbf074f42a203ac0b9
40 | (1) 7e06428bb2ad698b277cd77607505abb00faed5a99a9bf8064c40787e1e7b745
41 | (2) 3719fd869bc9d310b3334ee69530fdae03106adef47dd8c584a1d14a29b41d84
42 | (3) 6fb3a3070d2c0b32a8a181d3a33ca5cc3d4dd958b95fa0a28a1c6c4df698f919
43 | (4) 7cf6be18e131638a83675805294017a81d7b7a40271df17f83071845678eaa96
44 | (5) 5b758a7b39afc142c3293d17b5af401afd80835e5708654188545eda45d52d95
45 | (6) 32b5b6b830a5fa5cd6796bde303ce89ee645a6952b1d4251d048ea68dde8c702
46 | (7) 03e64537cef8909d54645c980c4d805be86930a095637fb7f7b22a9d2fb58e42
47 | (8) e6edb1ee507a967780f63d03e88135708d67d62a56611a9cff6144a596edceab
48 | (9) 0cc66101e2efe5bb72776925c878dfc2a934bb87787f3fe6f56ed6eecc70589e
49 |
50 | -------
51 |
52 | Ganache Seed
53 | candy maple cake sugar pudding cream honey rich smooth crumble sweet treat
54 |
55 | Available Accounts
56 | ==================
57 | (0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
58 | (1) 0xf17f52151ebef6c7334fad080c5704d77216b732
59 | (2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
60 | (3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
61 | (4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
62 | (5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
63 | (6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
64 | (7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
65 | (8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
66 | (9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
67 |
68 | Private Keys
69 | ==================
70 | (0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
71 | (1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
72 | (2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1
73 | (3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c
74 | (4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418
75 | (5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63
76 | (6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8
77 | (7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7
78 | (8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4
79 | (9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5
80 |
81 | -------
82 |
83 | BIP39 example seed
84 | wolf juice proud gown wool unfair wall cliff insect more detail hub
85 |
86 | BIP32 root
87 | xprv9s21ZrQH143K2Q5FjzwmUXKS9adFPhHhKSGiWhvxoXBwBA5FzXEe3oF3RdzWKUEjuFH1MAHsvZpfBHmcZxHRLf6bR1GBzJLrmc5uGso6rNE
88 |
89 | Available Accounts
90 | ==================
91 | (0) 0x6adca879124a3e9a87b4b55a9ada0119e4468941
92 | (1) 0xe1544a42ae1e21de1dc2e8f689dd3ae5fd64d507
93 | (2) 0x9c1f74baf574a4fd56ac4d73dfbdb10559734a14
94 | (3) 0x1745ec0c503d3c88f0af096eb7e0407ef934f153
95 | (4) 0x11e27593a8ee5a98f9b2e752fabb159c7837d49f
96 | (5) 0xf5484b9e3928576915d275e82e6af1539f3a9597
97 | (6) 0x7e0da4dc380249ea4919910b3ca8dc9d023fe7be
98 | (7) 0x15fb650736bace2f76f527307cf6c1639642e066
99 | (8) 0xd5326ba2c5924912a5c773835ad521c925af0d00
100 | (9) 0xe518bf0ebf9da4ba0342ea5d3213cc9279002d8a
101 |
102 | Private Keys
103 | ==================
104 | (0) 9d147484b814e14c7c6d546325e493e962825045ba5f6407c199ffabf226b28d
105 | (1) ae343294259b84aaaa12ffa4b91a1dbea46d2760c5506e62e2e698582398752f
106 | (2) 55d226c0e62029b20a3e6239268d159a555da0097618102133b6bb9b9c4ef968
107 | (3) aa2fffcbf8c3cf4508c71925f8bf87d9e9b7240fe868a6ac4d846ef4e66e75cf
108 | (4) de61c4d9645f3ac9d9e93d1f05eee866179e4f4b0605bf52d4797f0df750d70f
109 | (5) f52301c634da761d51848448d6a22f49161e0f5f22cc83d393cf5a44698f2c44
110 | (6) a8005637219801f87ddd7e248c2e8d0c3013c0ebb450b35ee64caf55e221f900
111 | (7) b132c35e45e79bbd371b9d3a1a46f580667a64293b88d74831a59a9eac4bf4e0
112 | (8) a6b09fb86fd6682abb1cad43b8aa53897bf10696f8b6934f0b1e4fa11a69cfce
113 | (9) 8a0037949e186f8810dfeb5b38ee657fcf43d12bbdd58dacd7684de3a98c87a2
114 |
--------------------------------------------------------------------------------
/code/web3js/web3js_demo/web3-contract-basic-interaction.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * @author Francisco Javier Rojas García
5 | */
6 |
7 | // Take a closer look at the web3 1.0 documentation for calling methods (it's very different from the 0.2x API).
8 | // https://stackoverflow.com/questions/48547268/smart-contract-method-is-not-a-function-in-web3
9 |
10 | console.log('Mastering Ethereum - web3.js basic interactions')
11 | console.log('Author: Francisco Javier Rojas García - fjrojasgarcia@gmail.com')
12 |
13 | const optionDefinitions = [
14 | { name: 'localRPC', alias: 'l', type: Boolean },
15 | { name: 'infuraFileToken', type: String, defaultOption: true }
16 | ]
17 |
18 | const commandLineArgs = require('command-line-args')
19 | const options = commandLineArgs(optionDefinitions)
20 |
21 | var Web3 = require('web3');
22 | var fs = require('fs')
23 |
24 | if (options.infuraFileToken && !options.localRPC) {
25 | console.log(options.infuraFileToken);
26 |
27 | // Loading an Infura Token from a file
28 | var infura_token = fs.readFileSync(options.infuraFileToken, 'utf8');
29 |
30 | // Show your Infura token
31 | console.log(infura_token);
32 |
33 | // Prepare your Infura host url
34 | var infura_host = `https://kovan.infura.io/${infura_token}`
35 |
36 | } else {
37 | console.log('Not argument found for infura token');
38 |
39 | // Prepare your Infura host url
40 | var infura_host = "https://kovan.infura.io"
41 |
42 | }
43 |
44 | // Show your Infura host url for your web3 connection
45 | console.log(infura_host);
46 |
47 | // Instantiate web3 provider
48 | var web3 = new Web3(infura_host);
49 |
50 | // Let's do some basic interactions at web3 level
51 | // Let's see the Protocol Version
52 | web3.eth.getProtocolVersion().then(function(protocolVersion) {
53 | console.log(`Protocol Version: ${protocolVersion}`);
54 | })
55 |
56 | // Now I'm curious about the current gas price
57 | web3.eth.getGasPrice().then(function(gasPrice) {
58 | console.log(`Gas Price: ${gasPrice}`);
59 | })
60 |
61 | // And, Whats the last mined block in my chain?
62 | web3.eth.getBlockNumber().then(function(blockNumber) {
63 | console.log(`Block Number: ${blockNumber}`);
64 | })
65 |
66 | // Now let's dive into some basics actions with a contract
67 | // We will use the contract at;
68 | // https://kovan.etherscan.io/address/0xd0a1e359811322d97991e03f863a0c30c2cf029c#code
69 |
70 | // First things first, let's initialize our contract address
71 | var our_contract_address = "0xd0A1E359811322d97991E03f863a0C30C2cF029C";
72 |
73 | // Let's see its balance
74 | web3.eth.getBalance(our_contract_address).then(function(balance) {
75 | console.log(`Balance of ${our_contract_address}: ${balance}`);
76 | })
77 |
78 | // Now let's see its byte code
79 | web3.eth.getCode(our_contract_address).then(function(code) {
80 | console.log("Contract code: ----------------------------------------------\n");
81 | console.log(code);
82 | console.log("-------------------------------------------------------------\n");
83 | })
84 |
85 | // Let's initialize our contract url in Etherescan for Kovan chain
86 | var etherescan_url = `http://kovan.etherscan.io/api?module=contract&action=getabi&address=${our_contract_address}`
87 | console.log(etherescan_url);
88 |
89 | var client = require('node-rest-client-promise').Client();
90 |
91 | // Now we are going to deal with the contract from web3.js in a non-block fashion (async mode)
92 | client.getPromise(etherescan_url)
93 | .then((client_promise) => {
94 | // Leave this two lines for fure object analisys
95 | //const util = require('util')
96 | //console.log(util.inspect(client_promise, false, null))
97 |
98 | // We get here our contract ABI
99 | our_contract_abi = JSON.parse(client_promise.data.result);
100 |
101 | // And now we create a promise to consume later
102 | return new Promise((resolve, reject) => {
103 | var our_contract = new web3.eth.Contract(our_contract_abi, our_contract_address);
104 | try {
105 | // If all goes well
106 | resolve(our_contract);
107 | } catch (ex) {
108 | // If something goes wrong
109 | reject(ex);
110 | }
111 | });
112 |
113 | })
114 | .then((our_contract) => {
115 | // Let's see our contract address
116 | console.log(`Our Contract address: ${our_contract._address}`);
117 |
118 | // or in this other way
119 | console.log(`Our Contract address in other way: ${our_contract.options.address}`);
120 |
121 | // Now our contract abi
122 | console.log("Our contract abi: " + JSON.stringify(our_contract.options.jsonInterface));
123 |
124 | // This is turning more interesting, let's see what's going with our contract methods
125 | // Now let's see our contract total supply in a callback fashion
126 | our_contract.methods.totalSupply().call(function(err, totalSupply) {
127 | if (!err) {
128 | console.log(`Total Supply with a callback: ${totalSupply}`);
129 | } else {
130 | console.log(err);
131 | }
132 | });
133 |
134 | // Or you can use the returned Promise instead of passing in the callback:
135 | our_contract.methods.totalSupply().call().then(function(totalSupply){
136 | console.log(`Total Supply with a promise: ${totalSupply}`);
137 | }).catch(function(err) {
138 | console.log(err);
139 | });
140 |
141 | })
142 |
--------------------------------------------------------------------------------
/code/auction_dapp/frontend/src/models/AuctionRepository.js:
--------------------------------------------------------------------------------
1 | import Config from '../config'
2 |
3 | export class AuctionRepository {
4 |
5 | web3 = null
6 | account = ''
7 | contractInstance = null
8 | gas = 4476768
9 |
10 | constructor(){
11 | this.gas = Config.GAS_AMOUNT
12 | }
13 |
14 | setWeb3(web3) {
15 | this.web3 = web3
16 | this.contractInstance = this.web3.eth.contract(Config.AUCTIONREPOSITORY_ABI).at(Config.AUCTIONREPOSITORY_ADDRESS)
17 | }
18 |
19 | getWeb3() {
20 | return this.web3
21 | }
22 |
23 | setAccount(account){
24 | this.account = account
25 | }
26 |
27 |
28 | getCurrentBlock() {
29 | return new Promise((resolve, reject ) => {
30 | this.web3.eth.getBlockNumber((err, blocknumber) => {
31 | if(!err) resolve(blocknumber)
32 | reject(err)
33 | })
34 | })
35 | }
36 |
37 | async watchIfCreated(cb) {
38 | const currentBlock = await this.getCurrentBlock()
39 | const eventWatcher = this.contractInstance.AuctionCreated({}, {fromBlock: currentBlock - 1, toBlock: 'latest'})
40 | eventWatcher.watch(cb)
41 | }
42 |
43 | async watchIfBidSuccess(cb) {
44 | const currentBlock = await this.getCurrentBlock()
45 | const eventWatcher = this.contractInstance.BidSuccess({}, {fromBlock: currentBlock - 1, toBlock: 'latest'})
46 | eventWatcher.watch(cb)
47 | }
48 |
49 | async watchIfCanceled(cb) {
50 | const currentBlock = await this.getCurrentBlock()
51 | const eventWatcher = this.contractInstance.AuctionCanceled({}, {fromBlock: currentBlock - 1, toBlock: 'latest'})
52 | eventWatcher.watch(cb)
53 | }
54 |
55 | async watchIfFinalized(cb) {
56 | const currentBlock = await this.getCurrentBlock()
57 | const eventWatcher = this.contractInstance.AuctionFinalized({}, {fromBlock: currentBlock - 1, toBlock: 'latest'})
58 | eventWatcher.watch(cb)
59 | }
60 | getCurrentBid(auctionId) {
61 | return new Promise(async (resolve, reject) => {
62 | try {
63 | this.contractInstance.getCurrentBid(auctionId, {from: this.account, gas: this.gas }, (err, transaction) => {
64 | if(!err) resolve(transaction)
65 | reject(err)
66 | })
67 | } catch(e) {
68 | reject(e)
69 | }
70 | })
71 | }
72 |
73 | getBidCount(auctionId) {
74 | return new Promise(async (resolve, reject) => {
75 | try {
76 | this.contractInstance.getBidsCount(auctionId, {from: this.account, gas: this.gas }, (err, transaction) => {
77 | if(!err) resolve(transaction)
78 | reject(err)
79 | })
80 | } catch(e) {
81 | reject(e)
82 | }
83 | })
84 | }
85 |
86 | getCount() {
87 | return new Promise(async (resolve, reject) => {
88 | try {
89 | this.contractInstance.getCount({from: this.account, gas: this.gas }, (err, transaction) => {
90 | if(!err) resolve(transaction)
91 | reject(err)
92 | })
93 | } catch(e) {
94 | reject(e)
95 | }
96 | })
97 | }
98 |
99 | bid(auctionId, price) {
100 | console.log(auctionId, this.web3.toWei(price, 'ether'))
101 | return new Promise(async (resolve, reject) => {
102 | try {
103 | this.contractInstance.bidOnAuction(auctionId, {from: this.account, gas: this.gas, value: this.web3.toWei(price, 'ether') }, (err, transaction) => {
104 | if(!err) resolve(transaction)
105 | reject(err)
106 | })
107 | } catch(e) {
108 | reject(e)
109 | }
110 | })
111 | }
112 |
113 | create(deedId, auctionTitle, metadata, startingPrice, blockDeadline) {
114 | return new Promise(async (resolve, reject) => {
115 | try {
116 |
117 | this.contractInstance.createAuction(Config.DEEDREPOSITORY_ADDRESS, deedId, auctionTitle, metadata, this.web3.toWei(startingPrice, 'ether'), blockDeadline, {from: this.account, gas: this.gas }, (err, transaction) => {
118 | if(!err) resolve(transaction)
119 | reject(err)
120 | })
121 | } catch(e) {
122 | reject(e)
123 | }
124 | })
125 | }
126 |
127 | cancel(auctionId) {
128 | return new Promise(async (resolve, reject) => {
129 | try {
130 | this.contractInstance.cancelAuction(auctionId, {from: this.account, gas: this.gas }, (err, transaction) => {
131 | if(!err) resolve(transaction)
132 | reject(err)
133 | })
134 | } catch(e) {
135 | reject(e)
136 | }
137 | })
138 | }
139 |
140 | finalize(auctionId) {
141 | return new Promise(async (resolve, reject) => {
142 | try {
143 | this.contractInstance.finalizeAuction(auctionId, {from: this.account, gas: this.gas }, (err, transaction) => {
144 | if(!err) resolve(transaction)
145 | reject(err)
146 | })
147 | } catch(e) {
148 | reject(e)
149 | }
150 | })
151 | }
152 |
153 | findById(auctionId) {
154 | return new Promise(async (resolve, reject) => {
155 | try {
156 | this.contractInstance.getAuctionById(auctionId, { from: this.account, gas: this.gas }, (err, transaction) => {
157 | if(!err) resolve(transaction)
158 | reject(err)
159 | })
160 | } catch(e) {
161 | reject(e)
162 | }
163 | })
164 | }
165 |
166 | }
--------------------------------------------------------------------------------
/web3-contract-basic-interaction.asciidoc:
--------------------------------------------------------------------------------
1 | == web3.js Contract basic interaction in a non-blocked (async) fashion
2 |
3 | === Description
4 | This script is for educational use and is based on web3@1.0.0-beta.29 web3.js version.
5 |
6 | It should be see as an introduction to web3.js.
7 |
8 | The web3.js library is a collection of modules which contain specific functionality for the Ethereum ecosystem.
9 |
10 | The web3.js object is an umbrella package to house all Ethereum related modules.
11 |
12 | This is the Ethereum compatible JavaScript API which implements the Generic JSON RPC spec.
13 |
14 | It run in a non-blocked (async) mode to accommodate in many of the methods provided by web3.js
15 |
16 | The most remarkable thing about this script is that you don’t need to run your own local node to use it, because it use the https://infura.io[Infura services].
17 |
18 | Anyway, I could adapt this script to be used with a local running node if it seems interesting.
19 |
20 | === Prepare the environment
21 | To see this script in action you should follow this simple steps.
22 |
23 | ==== Check you have a valid npm version
24 | ----
25 | $ npm -v
26 | 5.6.0
27 | ----
28 |
29 | ==== If you don't have already done, initialize your package
30 | ----
31 | $ npm init
32 | ----
33 |
34 | ==== Install basic dependences
35 | ----
36 | npm i command-line-args
37 | npm i web3
38 | npm i node-rest-client-promise
39 | ----
40 |
41 | This will update your package.json cofiguracion file with your new dependences.
42 |
43 | ==== Node.js script execution
44 |
45 | Basic execution
46 | ----
47 | code/web3js/web3-contract-basic-interaction.js
48 | ----
49 |
50 | Use your own Infura Token
51 | ----
52 | code/web3js/web3-contract-basic-interaction.js --infuraFileToken /path/to/file/with/infura_token
53 |
54 | or
55 |
56 | code/web3js/web3-contract-basic-interaction.js /path/to/file/with/infura_token
57 | ----
58 |
59 | == What the hell this script do?
60 | This script try to introduce to the basic use of web3.js
61 |
62 | Despite some utilities provided by the script what it really do is ...
63 |
64 | === web3 provider
65 | We use web3.js Web3 object to obtain a basic web3 provider.
66 |
67 | ----
68 | var web3 = new Web3(infura_host);
69 | ----
70 |
71 | === Let's do some basic interactions at web3 level
72 | Let's see the Protocol Version.
73 |
74 | ----
75 | web3.eth.getProtocolVersion().then(function(protocolVersion) {
76 | console.log(`Protocol Version: ${protocolVersion}`);
77 | })
78 | ----
79 |
80 | Now I'm curious about the current gas price.
81 |
82 | ----
83 | web3.eth.getGasPrice().then(function(gasPrice) {
84 | console.log(`Gas Price: ${gasPrice}`);
85 | })
86 | ----
87 |
88 | And, Whats the last mined block in my chain?
89 |
90 | ----
91 | web3.eth.getBlockNumber().then(function(blockNumber) {
92 | console.log(`Block Number: ${blockNumber}`);
93 | })
94 | ----
95 |
96 | === Now let's dive into some basics actions with a contract
97 | We will use the contract at;
98 | https://kovan.etherscan.io/address/0xd0a1e359811322d97991e03f863a0c30c2cf029c#code
99 |
100 | First things first, let's initialize our contract address.
101 |
102 | ----
103 | var our_contract_address = "0xd0A1E359811322d97991E03f863a0C30C2cF029C";
104 | ----
105 |
106 | Let's see its balance.
107 |
108 | ----
109 | web3.eth.getBalance(our_contract_address).then(function(balance) {
110 | console.log(`Balance of ${our_contract_address}: ${balance}`);
111 | })
112 | ----
113 |
114 | Now let's see its byte code.
115 |
116 | ----
117 | web3.eth.getCode(our_contract_address).then(function(code) {
118 | console.log(code);
119 | })
120 | ----
121 |
122 | === Now we are going to deal with the contract
123 | We prepare our environment to interact with the Etherescan explorer API.
124 |
125 | Let's initialize our contract url in the Etherescan explorer API for the Kovan chain.
126 |
127 | ----
128 | var etherescan_url = `http://kovan.etherscan.io/api?module=contract&action=getabi&address=${our_contract_address}`
129 | ----
130 |
131 | And now get a rest client to operate with.
132 |
133 | ----
134 | var client = require('node-rest-client-promise').Client();
135 | ----
136 |
137 | Let's get a client promise.
138 |
139 | ----
140 | client.getPromise(etherescan_url)
141 | ----
142 |
143 | And once we got a valid client promise, then we can use it.
144 |
145 | Now we get here our contract ABI from the client promise (from the Etherescan explorer).
146 | ----
147 | .then((client_promise) => {
148 | our_contract_abi = JSON.parse(client_promise.data.result);
149 | ----
150 |
151 | And now we create our contract object as a promise to consume later.
152 | ----
153 | return new Promise((resolve, reject) => {
154 | var our_contract = new web3.eth.Contract(our_contract_abi, our_contract_address);
155 | try {
156 | // If all goes well
157 | resolve(our_contract);
158 | } catch (ex) {
159 | // If something goes wrong
160 | reject(ex);
161 | }
162 | });
163 | })
164 | ----
165 |
166 | If our contract promise return well let's consume it.
167 | ----
168 | .then((our_contract) => {
169 | ----
170 |
171 | Let's see our contract address.
172 | ----
173 | console.log(`Our Contract address: ${our_contract._address}`);
174 | ----
175 |
176 | or in this other way.
177 | ----
178 | console.log(`Our Contract address in other way: ${our_contract.options.address}`);
179 | ----
180 |
181 | Now our contract abi.
182 | ----
183 | console.log("Our contract abi: " + JSON.stringify(our_contract.options.jsonInterface));
184 | ----
185 |
186 | === This is turning more interesting, let's see what's going on with our contract
187 | Now let's see our contract total supply in a callback fashion;
188 |
189 | ----
190 | our_contract.methods.totalSupply().call(function(err, totalSupply) {
191 | if (!err) {
192 | console.log(`Total Supply with a callback: ${totalSupply}`);
193 | } else {
194 | console.log(err);
195 | }
196 | });
197 | ----
198 |
199 | Or you can use the returned Promise instead of passing in the callback;
200 | ----
201 | our_contract.methods.totalSupply().call().then(function(totalSupply){
202 | console.log(`Total Supply with a promise: ${totalSupply}`);
203 | }).catch(function(err) {
204 | console.log(err);
205 | });
206 | ----
207 |
--------------------------------------------------------------------------------
/contrib/aws-network-operation.asciidoc:
--------------------------------------------------------------------------------
1 | [[_anchor_operate_private_network]]
2 | == Operating a private Ethereum network
3 |
4 | Once the set-up for private network is completed, the network has the following nodes are launched:
5 |
6 | * Ethereum boot node for other machines to look up for peering.
7 | * Ethereum mining node that does mining.
8 | * Ethereum RPC node that exposes RPC port for programmatic access.
9 | * Ethereum stand alone node that does not mine or expose API.
10 |
11 | [NOTE]
12 | ====
13 | The remainder of this section will use peering of nodes using `bootnodes`.
14 | ====
15 |
16 | For a quick summary on launching a private network, see link:aws-networ-setup.asciidoc#Summary[AWS network set-up summary]. To learn more about setting up the network, see link:aws-network-setup.asciidoc[AWS network set-up].
17 |
18 | Now, the network is ready for deployment of smart contracts. The steps to be followed for deployment of contracts are as follows:
19 |
20 | . Account set-up <<_anchor_account_set_up>>
21 | . Deploy contract <<_anchor_deploy_contract>>
22 | . Interacting with the contract <<_anchor_interacting_with_the_contract>>
23 |
24 | [[_anchor_account_set_up]]
25 | === Account set-up
26 | While account could be set-up on any node, for this section, accounts will be created for mining node and RPC node to store the mining reward and end-point activities only. To create an account, log on to the mining node and run this command.
27 |
28 | [[_code_new_account]]
29 | .Account creation
30 | [source,bash]
31 | ----
32 | geth --datadir eth-priv account new // 1
33 | ----
34 | <1> Note the `datadir` flag; it indicates that, the account is for a private network. Note the generated address. Running this account will prompt for password.
35 |
36 | [NOTE]
37 | ====
38 | *There is no 'Forgot password' option for your account. Therefore, keep your password at a safe place!*
39 | ====
40 |
41 |
42 | [[_anchor_deploy_contract]]
43 | === Deploy contract
44 |
45 | [TIP]
46 | ====
47 | This chapter uses `truffle` for contract development and deployment.
48 | ====
49 |
50 | For this section, we will deploy the `METoken` contract as described in the link:tokens.asciidoc[Tokens] section. Once the contract has been developed and compiled successfully, we will migrate to the private network. A quick introduction to set-up is provided here.
51 |
52 | . Install `truffle`, run `npm install -g truffle`.
53 | . Clone repository `https://github.com/chainhead/MET`
54 | . In the cloned repository, go to `MET/METtoken` and run `npm install` to install dependencies.
55 | . At `MET/METtoken`, run `truffle compile` to compile the contracts.
56 |
57 | To migrate the contract, `truffle` needs to know about the network. This information will be provided in the `truffle.js` configuration file. A sample file is provided link:../code/aws/truffle.js[here]. The information is provided via another network, with name as `aws`, added to the array of `networks` shown as an example below.
58 |
59 | [[_code_truffle_config_private_network]]
60 | .Truffle configuration
61 | [source,json]
62 | ----
63 | aws: { // Private network on AWS
64 | network_id: "15", // 1
65 | host: "IP address RPC node", // 2
66 | port: 8545, // 3
67 | gas: 6721975, // 4
68 | from : "0xaddresstopayforgas" // 5
69 | }
70 | ----
71 |
72 | <1> The `network_id` as defined in `genesis.json` document.
73 | <2> The public IP address of the EC2 instance node running `geth` with RPC node exposed.
74 | <3> The RPC port number of the EC2 instance hosting Ethereum RPC node. Default is `8545`.
75 | <4> Gas limit used for deploys. Default is `4712388`.
76 | <5> An account with sufficient ether to pay gas for contract interactions. This will be the address generated at <<_code_new_account>>.
77 |
78 | To deploy the contract with `truffle`, run the command below.
79 | [[_code_deploy_contract]]
80 | .Truffle network migration
81 | [source,bash]
82 | ----
83 | truffle migrate --network aws // 1
84 | Deploying Migrations...
85 | ... 0x3d04e043f82e323fb326a75f6da382e6687be1df4d00f026207f1b8e4d892fe8 // 2
86 |
87 | ----
88 |
89 | <1> The `--network` flag is set to the value of `aws` as defined in `truffle.js` file.
90 | <2> Output of deployment showing the address where the contrat was deployed.
91 |
92 | The contract creation can be seen on the mining node console output also as shown below.
93 | [[_code_deployment_output]]
94 | [source,bash]
95 | ----
96 | INFO [03-26|23:15:55] Submitted contract creation fullhash=0x3d04e043f82e323fb326a75f6da382e6687be1df4d00f026207f1b8e4d892fe8 contract=0xD33b0dCFFA52D2188E22BD01826d063265ec3e83
97 | ----
98 |
99 | [[_anchor_interacting_with_the_contract]]
100 | === Interacting with the contract
101 | To interact with the deployed contract, launch console as shown below. To learn more about the truffle console, see http://truffleframework.com/docs/getting_started/console[here].
102 |
103 | [[_code_launch_console]]
104 | [source,bash]
105 | ----
106 | truffle console --network aws // 1
107 | ----
108 |
109 | <1> The `--network` flag is set to the value of `aws` as defined in `truffle.js` file.
110 |
111 |
112 | ==== Use faucet
113 |
114 | ==== Buy MET
115 |
116 | [[_anchor_operation_summary]]
117 | == Summary
118 | To summarize working with private Ethereum network, here are the steps used:
119 |
120 | . Launch a private Ethereum network as described in link:aws-network-setup.asciidoc[AWS network set-up]
121 | . Once the nodes are launched and configured for genesis on each of the nodes, run the following commands on nodes.
122 |
123 | [[_table_command_summary]]
124 | .Ethereum nodes - Command summary
125 | |==================================================================================================================================
126 | | Node| Command | Remarks
127 | |Boot node | `bootnode --nodekey=bootnode.key` | Generate `bootnode.key` in advance. See <>
128 | |Standalone node | `geth --bootnodes 'enode://' --datadir eth-priv console` | Change `[::]` in `enode://` URI from `bootnode` output above with public IP address of the machine where `bootnode` is running.
129 | |RPC node | `geth --bootnodes 'enode://' --datadir eth-priv --rpc --rpcapi "web3,eth,personal" --rpcaddr "0.0.0.0" --rpccorsdomain "\*" console` | Opens RPC port for contract interaction. *NOTE* the values of `--rpcaddr "0.0.0.0" --rpccorsdomain "\*"` are discouraged!
130 | |Mining node | `geth --bootnodes 'enode://' --datadir eth-priv ---mine -rpc --rpcapi "web3,eth,personal" --rpcaddr "0.0.0.0" --rpccorsdomain "\*"` | Starts mining _and_ opens RPC port. An account should exist before running this command.
131 | |==================================================================================================================================
132 |
--------------------------------------------------------------------------------
/code/auction_dapp/backend/contracts/ERC721/ERC721Token.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.18;
2 |
3 | import "./ERC721.sol";
4 | import "./DeprecatedERC721.sol";
5 | import "./ERC721BasicToken.sol";
6 |
7 |
8 | /**
9 | * @title Full ERC721 Token
10 | * This implementation includes all the required and some optional functionality of the ERC721 standard
11 | * Moreover, it includes approve all functionality using operator terminology
12 | * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
13 | */
14 | contract ERC721Token is ERC721, ERC721BasicToken {
15 | // Token name
16 | string internal name_;
17 |
18 | // Token symbol
19 | string internal symbol_;
20 |
21 | // Mapping from owner to list of owned token IDs
22 | mapping (address => uint256[]) internal ownedTokens;
23 |
24 | // Mapping from token ID to index of the owner tokens list
25 | mapping(uint256 => uint256) internal ownedTokensIndex;
26 |
27 | // Array with all token ids, used for enumeration
28 | uint256[] internal allTokens;
29 |
30 | // Mapping from token id to position in the allTokens array
31 | mapping(uint256 => uint256) internal allTokensIndex;
32 |
33 | // Optional mapping for token URIs
34 | mapping(uint256 => string) internal tokenURIs;
35 |
36 | /**
37 | * @dev Constructor function
38 | */
39 | function ERC721Token(string _name, string _symbol) public {
40 | name_ = _name;
41 | symbol_ = _symbol;
42 | }
43 |
44 | /**
45 | * @dev Gets the token name
46 | * @return string representing the token name
47 | */
48 | function name() public view returns (string) {
49 | return name_;
50 | }
51 |
52 | /**
53 | * @dev Gets the token symbol
54 | * @return string representing the token symbol
55 | */
56 | function symbol() public view returns (string) {
57 | return symbol_;
58 | }
59 |
60 | /**
61 | * @dev Returns an URI for a given token ID
62 | * @dev Throws if the token ID does not exist. May return an empty string.
63 | * @param _tokenId uint256 ID of the token to query
64 | */
65 | function tokenURI(uint256 _tokenId) public view returns (string) {
66 | require(exists(_tokenId));
67 | return tokenURIs[_tokenId];
68 | }
69 |
70 | /**
71 | * @dev Gets the token ID at a given index of the tokens list of the requested owner
72 | * @param _owner address owning the tokens list to be accessed
73 | * @param _index uint256 representing the index to be accessed of the requested tokens list
74 | * @return uint256 token ID at the given index of the tokens list owned by the requested address
75 | */
76 | function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) {
77 | require(_index < balanceOf(_owner));
78 | return ownedTokens[_owner][_index];
79 | }
80 |
81 | /**
82 | * @dev Gets the total amount of tokens stored by the contract
83 | * @return uint256 representing the total amount of tokens
84 | */
85 | function totalSupply() public view returns (uint256) {
86 | return allTokens.length;
87 | }
88 |
89 | /**
90 | * @dev Gets the token ID at a given index of all the tokens in this contract
91 | * @dev Reverts if the index is greater or equal to the total number of tokens
92 | * @param _index uint256 representing the index to be accessed of the tokens list
93 | * @return uint256 token ID at the given index of the tokens list
94 | */
95 | function tokenByIndex(uint256 _index) public view returns (uint256) {
96 | require(_index < totalSupply());
97 | return allTokens[_index];
98 | }
99 |
100 | /**
101 | * @dev Internal function to set the token URI for a given token
102 | * @dev Reverts if the token ID does not exist
103 | * @param _tokenId uint256 ID of the token to set its URI
104 | * @param _uri string URI to assign
105 | */
106 | function _setTokenURI(uint256 _tokenId, string _uri) internal {
107 | require(exists(_tokenId));
108 | tokenURIs[_tokenId] = _uri;
109 | }
110 |
111 | /**
112 | * @dev Internal function to add a token ID to the list of a given address
113 | * @param _to address representing the new owner of the given token ID
114 | * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
115 | */
116 | function addTokenTo(address _to, uint256 _tokenId) internal {
117 | super.addTokenTo(_to, _tokenId);
118 | uint256 length = ownedTokens[_to].length;
119 | ownedTokens[_to].push(_tokenId);
120 | ownedTokensIndex[_tokenId] = length;
121 | }
122 |
123 | /**
124 | * @dev Internal function to remove a token ID from the list of a given address
125 | * @param _from address representing the previous owner of the given token ID
126 | * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
127 | */
128 | function removeTokenFrom(address _from, uint256 _tokenId) internal {
129 | super.removeTokenFrom(_from, _tokenId);
130 |
131 | uint256 tokenIndex = ownedTokensIndex[_tokenId];
132 | uint256 lastTokenIndex = ownedTokens[_from].length.sub(1);
133 | uint256 lastToken = ownedTokens[_from][lastTokenIndex];
134 |
135 | ownedTokens[_from][tokenIndex] = lastToken;
136 | ownedTokens[_from][lastTokenIndex] = 0;
137 | // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
138 | // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
139 | // the lastToken to the first position, and then dropping the element placed in the last position of the list
140 |
141 | ownedTokens[_from].length--;
142 | ownedTokensIndex[_tokenId] = 0;
143 | ownedTokensIndex[lastToken] = tokenIndex;
144 | }
145 |
146 | /**
147 | * @dev Internal function to mint a new token
148 | * @dev Reverts if the given token ID already exists
149 | * @param _to address the beneficiary that will own the minted token
150 | * @param _tokenId uint256 ID of the token to be minted by the msg.sender
151 | */
152 | function _mint(address _to, uint256 _tokenId) internal {
153 | super._mint(_to, _tokenId);
154 |
155 | allTokensIndex[_tokenId] = allTokens.length;
156 | allTokens.push(_tokenId);
157 | }
158 |
159 | /**
160 | * @dev Internal function to burn a specific token
161 | * @dev Reverts if the token does not exist
162 | * @param _owner owner of the token to burn
163 | * @param _tokenId uint256 ID of the token being burned by the msg.sender
164 | */
165 | function _burn(address _owner, uint256 _tokenId) internal {
166 | super._burn(_owner, _tokenId);
167 |
168 | // Clear metadata (if any)
169 | if (bytes(tokenURIs[_tokenId]).length != 0) {
170 | delete tokenURIs[_tokenId];
171 | }
172 |
173 | // Reorg all tokens array
174 | uint256 tokenIndex = allTokensIndex[_tokenId];
175 | uint256 lastTokenIndex = allTokens.length.sub(1);
176 | uint256 lastToken = allTokens[lastTokenIndex];
177 |
178 | allTokens[tokenIndex] = lastToken;
179 | allTokens[lastTokenIndex] = 0;
180 |
181 | allTokens.length--;
182 | allTokensIndex[_tokenId] = 0;
183 | allTokensIndex[lastToken] = tokenIndex;
184 | }
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/devp2p-protocol.asciidoc:
--------------------------------------------------------------------------------
1 | ////
2 | Source:
3 | https://github.com/ethereum/devp2p/blob/master/rlpx.md#node-discovery
4 | https://github.com/ethereum/wiki/wiki/%C3%90%CE%9EVp2p-Wire-Protocol
5 | https://github.com/ethereum/wiki/wiki/Ethereum-Wire-Protocol
6 | https://github.com/ethereum/wiki/wiki/Adaptive-Message-IDs
7 | License: Not defined yet
8 | Added By: @fjrojasgarcia
9 | ////
10 |
11 | [[communications_between_nodes]]
12 | == Communications between nodes - A simplified vision
13 |
14 | Ethereum nodes communicate among themselves using a simple wire protocol forming a virtual or overlay _well-formed network_.
15 | To achieve this goal, this protocol called *ÐΞVp2p*, uses technologies and standards such as *RLP*.
16 |
17 | [[transport_protocol]]
18 | === Transport protocol
19 | In order to provide confidentiality and protect against network disruption, *ÐΞVp2p* nodes use *RLPx* messages, an encrypted and authenticated _transport protocol_.
20 | *RLPx* utilizes a routing algorithm similiar to *Kademlia*, which is a distributed hash table (*DHT*) for decentralized peer-to-peer computer networks.
21 |
22 | *RLPx*, as an underlying transport protocol, allows among other, _"Node Discovery and Network Formation"_.
23 | Another remarkable feature of *RLPx* is the support of _multiple protocols_ over a single connection.
24 |
25 | When *ÐΞVp2p* nodes communicate via Internet (as they usually do), they use TCP, which provides a connection-oriented medium, but actually *ÐΞVp2p* nodes communicate in terms of packets, using the so-called facilities (or messages) provided by the underlying transport protocol *RLPx*, allowing them to communicate sending and receiving packets.
26 |
27 | Packets are _dynamically framed_, prefixed with an _RLP_ encoded header, encrypted and authenticated. Multiplexing is achieved via the frame header which specifies the destination protocol of a packet.
28 |
29 | ==== Encrypted Handshake
30 | Connections are established via a handshake and, once established, packets are encrypted and encapsulated as frames.
31 |
32 | This handshake will be carried out in two phases, the first phase involves the keys exchange and the second phase will perform authentication, and as a part of *DEVp2p*, will also exchange the capabilities of each node.
33 |
34 | ==== Security - Basic considerations
35 |
36 | All cryptographic operations are based on *secp256k1* and each node is expected to maintain a static private key which is saved and restored between sessions.
37 |
38 | Until encryption is implemented, packets have a timestamp property to reduce the window of time for carrying out replay attacks.
39 | It is recommended that the receiver only accepts packets created within the last 3 seconds.
40 |
41 | Packets are signed. Verification is performed by recovering the public key from the signature and checking that it matches an expected value.
42 |
43 | [[devp2p_messages_subprotocols]]
44 | === ÐΞVp2p messages and Sub-protocols
45 | With *RLP* we can encode different types of payloads, whose types are determined by the integer value used in the first entry of the RLP.
46 | In this way, *ÐΞVp2p*, the _basic wire protocol_, support _arbitrary sub-protocols_.
47 |
48 | _Message IDs_ between `0x00-0x10` are reserved for *ÐΞVp2p* messages. Therefore, the message IDs of _sub-protocols_ are assumed to be from `0x10` onwards.
49 |
50 | Sub-protocols that are not shared between peers are _ignored_.
51 | If multiple versions of the same (equal name) sub-protocol are shared, _the numerically highest wins_.
52 |
53 | ==== Basic establishment of communication - Basic ÐΞVp2p message
54 |
55 | As a very basic example, when two peers initiate their communication, each one greets the other with a special *ÐΞVp2p* message called *"Hello"*, which is identified by the `0x00` message ID.
56 | Through this particular *ÐΞVp2p* *"Hello"* message, each node will disclose to its peer relevant data that will allow the communication to begin at a very basic level.
57 |
58 | In this step, each peer will know the following information about his peer.
59 |
60 | - The implemented *version* of the P2P protocol. Now must be `1`.
61 | - The *client software identity*, as a human-readable string (e.g. `Ethereum(++)/1.0.0`).
62 | - Peer *capability name* as an ASCII string of length 3. Currently supported capability names are `eth` and `shh`.
63 | - Peer *capability version* as a positive integer. Currently supported versions are `34` for `eth`, and `1` for `shh`.
64 | - The *port* that the client is listening on. If `0` it indicates the client is not listening.
65 | - The *Unique Identity of the node* specified as a 512-bit hash.
66 |
67 | ==== Disconnection - Basic ÐΞVp2p message
68 | To carry out an ordered disconnection, the node that wants to disconnect, will send a *ÐΞVp2p* message called *"Disconnect"*, which is identified by the _"0x01"_ message id. Furthermore, the node specifies the reason for the disconnection using the parameter *"reason"*.
69 |
70 | The *"reason"* parameter can take values from `0x00` to `0x10`, e.g. `0x00` represents the reason *"Disconnect requested"* and `0x04` represents *"Too many peers"*.
71 |
72 | ==== Status - Ethereum sub-protocol example
73 | This sub-protocol is identified by the `+0x00` message-id.
74 |
75 | This message should be sent after the initial handshake and prior to any Ethereum related messages and inform of its current state.
76 |
77 | To do this, the node disclose to its peer the following data;
78 |
79 | - The *Protocol version*.
80 | - The *Network Id*.
81 | - The *Total Difficulty of the best chain*.
82 | - The *Hash of the best known block*.
83 | - The *Hash of the Genesis block*.
84 |
85 | [[known_current_networks]]
86 | ===== Known current network Ids
87 | About networks ids here is a list of those currently known;
88 |
89 | - 0: *Olympic*; Ethereum public pre-release testnet
90 | - 1: *Frontier*; Homestead, Metropolis, the Ethereum public main network
91 | - 1: *Classic*; The (un)forked public Ethereum Classic main network, chain ID 61
92 | - 1: *Expanse*; An alternative Ethereum implementation, chain ID 2
93 | - 2: *Morden*; The public Ethereum testnet, now Ethereum Classic testnet
94 | - 3: *Ropsten*; The public cross-client Ethereum testnet
95 | - 4: *Rinkeby*: The public Geth Ethereum testnet
96 | - 42: *Kovan*; The public Parity Ethereum testnet
97 | - 77: *Sokol*; The public POA testnet
98 | - 99: *POA*; The public Proof of Authority Ethereum network
99 | - 7762959: *Musicoin*; The music blockchain
100 |
101 | ==== GetBlocks - Another sub-protocol example
102 | This sub-protocol is identified by the `+0x05` message-id.
103 |
104 | With this message the node requests its peer the specified blocks each by its own hash.
105 |
106 | The way to request the nodes is through a list with all the hashes of them, taking the message the following form;
107 | ....
108 | [+0x05: P, hash_0: B_32, hash_1: B_32, ...]
109 | ....
110 |
111 | The requesting node must not have a response message containing all the requested blocks, in which case it must request again those that have not been sent by its peer.
112 |
113 | === Node identity and reputation
114 | The identity of a *ÐΞVp2p* node is a *secp256k1* public key.
115 |
116 | Clients are free to mark down new nodes and use the node ID as a means of _determining a node's reputation_.
117 |
118 | They can store ratings for given IDs and give preference accordingly.
119 |
--------------------------------------------------------------------------------
/code/jupyter_notebook/.ipynb_checkpoints/keys_and_addresses_python_notebook-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Keys and Addresses Exercises"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "### Requirements\n",
15 | "\n",
16 | " $ pip3 install ethereum\n",
17 | " \n",
18 | " $ pip3 install bitcoin\n",
19 | " \n",
20 | " $ pip3 install pycryptodomex\n",
21 | " \n",
22 | " $ pip3 install jupyter\n"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": 35,
28 | "metadata": {},
29 | "outputs": [],
30 | "source": [
31 | "# Import libraries\n",
32 | "\n",
33 | "\n",
34 | "# Vitalik Buterin's Python Library for bitcoin\n",
35 | "# No longer maintained!\n",
36 | "# https://pypi.python.org/pypi/bitcoin/1.1.42\n",
37 | "import bitcoin\n",
38 | "\n",
39 | "# Vitalik Buterin's Python Library for Ethereum\n",
40 | "# https://github.com/ethereum/pyethereum\n",
41 | "import ethereum\n",
42 | "\n",
43 | "# Wrong source of SHA3 (FIPS-202 not Keccak-256)\n",
44 | "from hashlib import sha3_256 as hashlib_sha3\n",
45 | "\n",
46 | "# Both FIP-202 SHA-3 and Keccak-256 from pycryptodomex\n",
47 | "from Crypto.Hash import SHA3_256 as crypto_sha3\n",
48 | "from Crypto.Hash import keccak as crypto_keccak\n",
49 | "\n",
50 | "# Ethereum library implements Keccak, but calls it sha3\n",
51 | "from ethereum.utils import sha3 as ethereum_sha3\n",
52 | "\n",
53 | "from rlp.utils import decode_hex, encode_hex\n"
54 | ]
55 | },
56 | {
57 | "cell_type": "code",
58 | "execution_count": 36,
59 | "metadata": {},
60 | "outputs": [],
61 | "source": [
62 | "privkey_hex = \"f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315\""
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": 37,
68 | "metadata": {},
69 | "outputs": [],
70 | "source": [
71 | "privkey = decode_hex(privkey_hex)"
72 | ]
73 | },
74 | {
75 | "cell_type": "code",
76 | "execution_count": 38,
77 | "metadata": {},
78 | "outputs": [],
79 | "source": [
80 | "# Use pybitcointools (bitcoin) library's elliptic curve functions to calculate the public key\n",
81 | "\n",
82 | "pubkey = bitcoin.privtopub(privkey)"
83 | ]
84 | },
85 | {
86 | "cell_type": "code",
87 | "execution_count": 39,
88 | "metadata": {},
89 | "outputs": [],
90 | "source": [
91 | "pubkey_hex = encode_hex(pubkey)"
92 | ]
93 | },
94 | {
95 | "cell_type": "code",
96 | "execution_count": 40,
97 | "metadata": {},
98 | "outputs": [
99 | {
100 | "name": "stdout",
101 | "output_type": "stream",
102 | "text": [
103 | "Public Key: 046e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0\n"
104 | ]
105 | }
106 | ],
107 | "source": [
108 | "print(\"Public Key: \" + pubkey_hex)"
109 | ]
110 | },
111 | {
112 | "cell_type": "code",
113 | "execution_count": 41,
114 | "metadata": {},
115 | "outputs": [
116 | {
117 | "name": "stdout",
118 | "output_type": "stream",
119 | "text": [
120 | "x (hex) : 6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b\n",
121 | "y (hex) : 83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0\n",
122 | "x (int) : 49790390825249384486033144355916864607616083520101638681403973749255924539515\n",
123 | "y (int) : 59574132161899900045862086493921015780032175291755807399284007721050341297360\n"
124 | ]
125 | }
126 | ],
127 | "source": [
128 | "pubkey_without_prefix = pubkey_hex[2:]\n",
129 | "x_hex = pubkey_without_prefix[:64]\n",
130 | "y_hex = pubkey_without_prefix[64:]\n",
131 | "print(\"x (hex) : \" + x_hex)\n",
132 | "print(\"y (hex) : \" + y_hex)\n",
133 | "\n",
134 | "x = int(x_hex, 16)\n",
135 | "y = int(y_hex, 16)\n",
136 | "print(\"x (int) : \", x)\n",
137 | "print(\"y (int) : \", y)"
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": 42,
143 | "metadata": {},
144 | "outputs": [
145 | {
146 | "data": {
147 | "text/plain": [
148 | "0"
149 | ]
150 | },
151 | "execution_count": 42,
152 | "metadata": {},
153 | "output_type": "execute_result"
154 | }
155 | ],
156 | "source": [
157 | "# Prove pubkey is a point on the curve\n",
158 | "\n",
159 | "# p is the prime order of the elliptic curve field\n",
160 | "p = 115792089237316195423570985008687907853269984665640564039457584007908834671663\n",
161 | "\n",
162 | "(x ** 3 + 7 - y**2) % p"
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": 50,
168 | "metadata": {},
169 | "outputs": [
170 | {
171 | "name": "stdout",
172 | "output_type": "stream",
173 | "text": [
174 | "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\n",
175 | "Hash Function is Keccak-256\n"
176 | ]
177 | }
178 | ],
179 | "source": [
180 | "# Which \"SHA3\" am I using?\n",
181 | "\n",
182 | "# Uncomment below to try various options\n",
183 | "#test_hash = hashlib_sha3(b\"\").hexdigest()\n",
184 | "#test_hash = crypto_sha3.new(b\"\").hexdigest()\n",
185 | "#test_hash = crypto_keccak.new(digest_bits=256, data=b\"\").hexdigest()\n",
186 | "#test_hash = encode_hex(ethereum_sha3(b\"\"))\n",
187 | "\n",
188 | "\n",
189 | "print(test_hash)\n",
190 | "\n",
191 | "if test_hash == \"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\":\n",
192 | " print(\"Hash Function is Keccak-256\")\n",
193 | "elif test_hash == \"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a\":\n",
194 | " print(\"Hash Function is FIP-202 SHA-3\")\n",
195 | "else: \n",
196 | " print(\"Oops! Can't identify SHA3\")\n",
197 | "\n"
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "execution_count": 51,
203 | "metadata": {},
204 | "outputs": [
205 | {
206 | "name": "stdout",
207 | "output_type": "stream",
208 | "text": [
209 | "Public Key Hash: 2a5bc342ed616b5ba5732269001d3f1ef827552ae1114027bd3ecf1f086ba0f9\n"
210 | ]
211 | }
212 | ],
213 | "source": [
214 | "hex_hash = encode_hex(ethereum_sha3(decode_hex(pubkey_without_prefix)))\n",
215 | "print (\"Public Key Hash: \" + hex_hash)"
216 | ]
217 | },
218 | {
219 | "cell_type": "code",
220 | "execution_count": 48,
221 | "metadata": {},
222 | "outputs": [
223 | {
224 | "name": "stdout",
225 | "output_type": "stream",
226 | "text": [
227 | "Ethereum Address: 0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9\n"
228 | ]
229 | }
230 | ],
231 | "source": [
232 | "print(\"Ethereum Address: 0x\" + hex_hash[24:])"
233 | ]
234 | }
235 | ],
236 | "metadata": {
237 | "kernelspec": {
238 | "display_name": "Python 3",
239 | "language": "python",
240 | "name": "python3"
241 | },
242 | "language_info": {
243 | "codemirror_mode": {
244 | "name": "ipython",
245 | "version": 3
246 | },
247 | "file_extension": ".py",
248 | "mimetype": "text/x-python",
249 | "name": "python",
250 | "nbconvert_exporter": "python",
251 | "pygments_lexer": "ipython3",
252 | "version": "3.6.3"
253 | }
254 | },
255 | "nbformat": 4,
256 | "nbformat_minor": 2
257 | }
258 |
--------------------------------------------------------------------------------
/contrib/node-communication-interaction.asciidoc:
--------------------------------------------------------------------------------
1 | [[node-communication-and-interaction]]
2 | Node Communication and Interaction
3 | ----------------------------------
4 |
5 | Ethereum defines a set of rules (protocol) in order for the
6 | nodes/clients to communicate and interact with each other. The wire
7 | protocol is used to describe the way information is structured and
8 | transferred between machines. The protocol may be either text-based or a
9 | binary protocol.
10 |
11 | Text-based protocols are typically optimized for human parsing and
12 | interpretation, and are therefore suitable whenever human inspection of
13 | protocol contents is required, such as during debugging and during early
14 | protocol development design phases.
15 |
16 | A binary protocol is a protocol which is intended to be read by a
17 | machine rather than a human being, as opposed to a plain text protocol
18 | such as IRC, SMTP, or HTTP. Binary protocols have the advantage of
19 | terseness, which translates into speed of transmission and
20 | interpretation.
21 |
22 | image:images/rlpx_rpc_xs.png[RLPx and JSONRPC]
23 |
24 | https://github.com/ethereum/wiki/wiki/%C3%90%CE%9EVp2p-Wire-Protocol
25 |
26 | https://en.wikipedia.org/wiki/Binary_protocol
27 |
28 | https://en.wikipedia.org/wiki/Text-based_protocol
29 |
30 | [[rlpx-binary-protocol]]
31 | RLPx (Binary Protocol)
32 | ~~~~~~~~~~~~~~~~~~~~~~
33 |
34 | In Ethereum, *peer-to-peer* communication and data transmition is
35 | achieved using the RLPx stack(Devp2p and RLP) which in terms uses a
36 | connection-oriented channel to transfer RLP encoded data.
37 |
38 | https://github.com/ethereum/devp2p/blob/master/rlpx.md
39 |
40 | https://github.com/ethereum/wiki/wiki/RLP
41 |
42 | [[jsonrpc-2.0-plain-text-protocol]]
43 | JSONRPC 2.0 (Plain-text Protocol)
44 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45 |
46 | In addition to RLPx, Ethereum provides a Plain-text JSON RPC
47 | request–response protocol which can be used by decentralized
48 | applications(DApps) or clients to **interact with a node**. Requests and
49 | responses are formatted in JSON and transferred over HTTP, Websockets and
50 | IPC.
51 |
52 | https://github.com/ethereum/wiki/wiki/JSON-RPC
53 |
54 | JSON-RPC is a stateless, light-weight remote procedure call (RPC)
55 | protocol. Primarily this specification defines several data structures
56 | and the rules around their processing. It is transport agnostic in that
57 | the concepts can be used within the same process, over sockets, over
58 | http, or in many various message passing environments.
59 |
60 | image:images/http_ws_ipc_jsonrpc.png[JSONRPC Transports]
61 |
62 | [[jsonrpc2.0-http]]
63 | JSONRPC2.0 HTTP
64 | ^^^^^^^^^^^^^^^
65 |
66 | Go-Ethereum exposes an HTTP server which accepts JSONRPC requests on
67 | port *8545* (default port). The following command runs Go-Ethereum
68 | client with rpc support:
69 |
70 | ....
71 | $ geth --rpc --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcport
72 | ....
73 |
74 | the `--rpccorsdomain` flag allows browsers to make cross-origin HTTP
75 | request from a different domain, protocol, or port.
76 |
77 | https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
78 |
79 | [[jsonrpc2.0-websockets]]
80 | JSONRPC2.0 WebSockets
81 | ^^^^^^^^^^^^^^^^^^^^^
82 |
83 | Similar to the HTTP server, a WebSockets connection may be established
84 | with the node on port *8546* (default port). Initially a request is sent
85 | to the HTTP server which is later upgraded to the WebSocket protocol
86 | providing full-duplex communication channels over a single TCP
87 | connection.
88 |
89 | ....
90 | $ geth --ws --wsaddr 0.0.0.0 --wsorigins "*" --wsport
91 | ....
92 |
93 | https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
94 |
95 | [[jsonrpc2.0-ipc]]
96 | JSONRPC2.0 IPC
97 | ^^^^^^^^^^^^^^
98 |
99 | An IPC socket is a communication channel for exchanging data between
100 | processes executing on the same host operating system. Go-Ethereum
101 | creates a socket (**geth.ipc**) by default which allows any process
102 | running on the host machine to communicate with the node.
103 |
104 | [[interacting-with-a-node-through-the-jsonrpc-interface]]
105 | Interacting with a Node through the JSONRPC interface
106 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107 |
108 | This section describes the process to run a private blockchain network
109 | and the interaction with the nodes on the network. The interaction
110 | process can also be applied to a node which runs on a public blockchain
111 | network.
112 |
113 | This setup is useful and cost effective for trying out Ethereum and
114 | test/develop DApps built on Ethereum without having to use real Ether.
115 | You either pre-generate or mine your own Ether on the private Ethereum
116 | Testnet.
117 |
118 | [[private-ethereum-testnet-setup]]
119 | Private Ethereum Testnet Setup
120 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
121 |
122 | 1.Download and install Geth
123 |
124 | Instructions:
125 | https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum
126 |
127 | 2.Create chain data folder and the genesis block for your private
128 | testnet
129 |
130 | ....
131 | $ mkdir -p $HOME/testnet/chaindata
132 | $ cd $HOME/testnet
133 | $ nano genesis.json
134 | ....
135 |
136 | Paste the following content in the `genesis.json` file :
137 |
138 | ....
139 | {
140 | "config": {
141 | "chainId": 245948721, //random value for your private testnet
142 | "homesteadBlock": 0,
143 | "eip155Block": 0,
144 | "eip158Block": 0
145 | },
146 | "difficulty": "0x400", //low difficulty-level to mine Ether
147 | "gasLimit": "0x8000000", //set this really high for testing
148 | "alloc": {}
149 | }
150 | ....
151 |
152 | 3.Initialize genesis block
153 |
154 | ....
155 | $ geth --identity "MobinPrivateTestNode" --datadir $HOME/testnet/chaindata init $HOME/testnet/genesis.json
156 | ....
157 |
158 | 4.Run the node with the custom genesis block
159 |
160 | ....
161 | $ geth --rpc --rpcaddr 0.0.0.0 --rpccorsdomain "*" --ws --wsaddr 0.0.0.0 --wsorigins "*" --datadir $HOME/testnet/chaindata --networkid 245948721
162 | ....
163 |
164 | 5.Attaching session to the node using the IPC socket
165 |
166 | ....
167 | $ geth attach $HOME/testnet/chaindata/geth.ipc
168 | ....
169 |
170 | 6.Create accounts and mine Ethers
171 |
172 | ....
173 | # Create account
174 | $ personal.newAccount()
175 |
176 | # Set the generated address to reward Ethers to
177 | $ miner.setEtherbase(personal.listAccounts[0])
178 |
179 | # Start mining
180 | miner.start()
181 |
182 | # Wait few minutes
183 | ....
184 |
185 | [[interact-with-the-node-through-the-jsonrpc-interface]]
186 | Interact with the node through the JSONRPC interface
187 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
188 |
189 | Develop apps which call few of the procedures... use different transport
190 | for each of them Need to demonstrate that no magic is done in web3.js,
191 | procedures are simply called in js using the jsonrpc interface
192 |
193 | [[jsonrpc-transport-http]]
194 | JSONRPC Transport: HTTP
195 | ^^^^^^^^^^^^^^^^^^^^^^^
196 |
197 | TODO: 1. Create a simple client to call the endpoint (js/golang) 2.
198 | Integrate in a web app
199 |
200 | [[jsonrpc-transport-websockets]]
201 | JSONRPC Transport: WebSockets
202 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
203 |
204 | TODO: 2. Create a simple client to call the endpoint (js/golang) 2.
205 | Integrate in a web app
206 |
207 | [[jsonrpc-transport-ipc]]
208 | JSONRPC Transport: IPC
209 | ^^^^^^^^^^^^^^^^^^^^^^
210 |
211 | TODO: 3. Develop a program to communicate with the node over the
212 | unixsocket
213 |
214 | [[web3.js]]
215 | Web3.js
216 | +++++++
217 |
218 | Explain that web3.js is the js lib which implements the above transports
219 | to communicate with a node and there is no magic ...
220 |
221 |
--------------------------------------------------------------------------------
/contrib/privacy-enhancing-patterns.asciidoc:
--------------------------------------------------------------------------------
1 | ////
2 | Source: https://medium.com/@SylTi/how-to-simply-create-ethereum-private-contracts-that-remains-enforceable-on-chain-30805a0b1d14
3 | License: MIT
4 | Added By: @SylTi
5 | ////
6 |
7 | == Privacy enhancing patterns
8 |
9 | === Commit-Reveal
10 |
11 | ==== Introduction
12 | This is commitment scheme that allows keeping a value private, until the reveal phase, while making it unchangeable.
13 |
14 | It his a widely used concept in cryptography that has many use cases with Ethereum smart contract, like the in the next pattern, in voting schemes (like PLCRVoting), in auctions, payment/state channels etc..
15 |
16 | ==== How does it work
17 |
18 | `hashOfvalue = keccak256(value, randomData)`
19 |
20 | By revealing the value and the randomData you can prove your commitment.
21 |
22 |
23 | === Privacy Judge
24 |
25 | ==== Introduction
26 | This pattern allows for a smart contract between 2 parties to remain private as long as they cooperate. Cooperation is incentivized by the use of a collateral.
27 |
28 | In case the other person is uncooperative or unresponsive, you can reveal the contract so it can be executed.
29 |
30 | This pattern can also be used with ERC20 tokens with a few simple changes.
31 |
32 | ==== How does it work
33 | This pattern is based on the Commit-Reveal pattern; It uses two type of commits:
34 |
35 | * Signed bytecode of a *resolver* contract
36 | * Funds deposited inside a *judge* contract
37 |
38 | It also adds an economic incentive to never get into the reveal phase keeping the *resolver* contract unpublished and completely private.
39 |
40 | The *judge* contract can only release the funds under one of those two conditions:
41 |
42 | * One of the parties send the total amount and get back is collateral as a reward for keeping the *resolver* contract private
43 | * One of the parties reveal the bytecode to the judge which results in the full amount stored inside the *judge* contract to be sent to the *resolver* contract that settles the transaction.
44 |
45 | ==== Example scenario
46 | Let’s take a very simple scenario where Alice and Bob want to bet on the price of Ethereum at a later date, but don’t want the world to know what they are betting on.
47 |
48 | The terms of this bet are the following: If the price of Ethereum is >= $1200 at the specified date Alice will pay Bob 10 ethers, if not Bob will pay Alice 10 ethers.
49 |
50 | This terms will be represented by the following smart contract:
51 |
52 | ===== Bet Implementation
53 |
54 | [source:Resolver Contract, solidity]
55 | ----
56 | pragma solidity ^0.4.18;
57 |
58 | contract Oracle {
59 | function getPrice(uint timestamp) public returns (uint) { return 1300; } // fake oracle
60 | }
61 |
62 | contract EtherPriceBet {
63 |
64 | Oracle public oracle;
65 | uint public resultTime;
66 | address public user1;
67 | address public user2;
68 |
69 | function EtherPriceBet() public {
70 | user1 = 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39;
71 | user2 = 0x6704fbfcd5ef766b287262fa2281c105d57246a6;
72 |
73 | oracle = new Oracle();
74 | resultTime = 1516051749 + 52 weeks;
75 | }
76 |
77 | function execute() public payable {
78 | require(now > resultTime);
79 | if (oracle.getPrice(resultTime) >= 1200)
80 | selfdestruct(user1);
81 | else
82 | selfdestruct(user2);
83 | }
84 | }
85 | ----
86 |
87 | Once both Alice and Bob have compile this smart contract, they both need to sign the resulting bytecode and exchange the resulting signature.
88 | Both of them need to check that the signature is valid by using `isContractValid()`.
89 |
90 | Then, one of them deploy the *judge* contract where they both send 10 ethers.
91 |
92 | ===== Judge Implementation
93 |
94 | This is a very simple implementation of the *judge* using the OpenZeppelin library and should not be considered production ready:
95 |
96 | [source: Judge Contract, solidity]
97 | ----
98 | pragma solidity ^0.4.18;
99 |
100 |
101 | import "../ECRecovery.sol";
102 | import "../math/SafeMath.sol";
103 |
104 | /**
105 | * @title Judge
106 | * @author SylTi
107 | * @dev This kind of construct allows for a smart contract between two entities to remains private as long as they cooperate with each other.
108 | * Cooperation is incentivized by the use of a collateral
109 | */
110 |
111 | contract Judge {
112 |
113 | using ECRecovery for bytes32;
114 | using SafeMath for uint256;
115 | address user1;
116 | address user2;
117 | uint amountToMatch;
118 | uint collateralPercentage = 1; //percentage of bet used as collateral. This is necessary to incentivize voluntary release of funds
119 | bool finalized;
120 |
121 | event LogContractSettlement(uint balance, address deployedAddress);
122 | event LogDeposit(address depositer, uint amount);
123 |
124 | modifier isUser() {
125 | require(msg.sender == user1 || msg.sender == user2);
126 | _;
127 | }
128 |
129 | function executeContract(bytes32 hashed, bytes signature, bytes code) public isUser {
130 | require(!finalized);
131 | require(isContractValid(hashed, signature, code));
132 | address deployedAddress;
133 | //create contract in assembly, and jump if deployment failed: no code at address
134 | assembly {
135 | deployedAddress := create(0, add(code, 0x20), mload(code))
136 | switch iszero(extcodesize(deployedAddress))
137 | case 1 { revert(0, 0) } // throw if contract failed to deploy
138 | }
139 | LogContractSettlement(this.balance, deployedAddress);
140 | assert(deployedAddress.call.gas(200000).value(this.balance)(bytes4(keccak256("execute()"))));
141 | finalized = true;
142 | }
143 |
144 | function isContractValid(bytes32 hashed, bytes signature, bytes code) public view returns (bool) {
145 | address signer;
146 | bytes32 proof;
147 |
148 | signer = hashed.recover(signature);
149 | if (signer != user1 && signer != user2) revert();
150 | proof = keccak256(code);
151 | return (proof == hashed);
152 | }
153 |
154 | function releasePayment() public isUser {
155 | if (msg.sender == user1) {
156 | assert(user2.send(this.balance.sub(this.balance.mul(collateralPercentage).div(100))));
157 | assert(user1.send(this.balance));
158 | }
159 | else if (msg.sender == user2) {
160 | assert(user1.send(this.balance.sub(this.balance.mul(collateralPercentage).div(100))));
161 | assert(user2.send(this.balance));
162 | }
163 | finalized = true;
164 | }
165 |
166 | function resetContract() public isUser {
167 | require(finalized);
168 | amountToMatch = 0;
169 | user1 = address(0);
170 | user2 = address(0);
171 | }
172 |
173 | function () public payable {
174 | require(user1 == address(0) || user2 == address(0));
175 | require(msg.value > 0);
176 | if (user1 == address(0)) {
177 | user1 = msg.sender;
178 | amountToMatch = msg.value;
179 | }
180 | else {
181 | require(msg.value == amountToMatch);
182 | require(msg.sender != user1);
183 | user2 = msg.sender;
184 | assert(this.balance == amountToMatch.mul(2));
185 | }
186 | LogDeposit(msg.sender, msg.value);
187 | }
188 | }
189 | ----
190 |
191 | ==== Possible Improvement
192 | We could allow for multiples *resolver* to be run in series (participants must agree on the previous result before signing the next *resolver*) by adding bidirectional payment capabilities to the *judge*.
193 |
194 | This could be done by adding a nonce, both users balances, and an amount to the hashed bytecode
195 |
196 | `proof = keccak256(code, nonce, balance1, balance2, amount);`
197 |
198 | We would also need to add a challenge period before the *resolver* can be executed to ensure one of the participants doesn't try to cheat by publishing a *resolver* with an old nonce.
199 |
--------------------------------------------------------------------------------