├── 0.1什么是以太坊.md ├── 1.1.1Linux.md ├── 1.1.2Mac.md ├── 1.1.3Windows.md ├── 1.1.4Docker.md ├── 1.1.5ARM.md ├── 1.1平台.md ├── 1.2备份和恢复.md ├── 1.3连接至网络.md ├── 1.4监控你的节点.md ├── 1.5设置集群.md ├── 1安装并运行节点.md ├── 2.1创建账户.md ├── 2.2导入你的presale钱包.md ├── 2.3列出账户和检查余额.md ├── 2.4发送以太.md ├── 2.管理账户.md ├── 3.1介绍.md ├── 3.2在geth上用CPU采矿.md ├── 3.3GPU挖矿.md ├── 4.1命令行接口和选项.md ├── 4.2JSON RPC API.md ├── 4.3JavaScript API for Dapps.md ├── 4.4JavaScript Console.md ├── 4.接口.md ├── 5.10测试合约及交易.md ├── 5.11注册服务.md ├── 5.12示例脚本.md ├── 5.13.1接待员.md ├── 5.13.2注册商.md ├── 5.13.3货币合约.md ├── 5.13.4众筹者.md ├── 5.13.5民主DAO.md ├── 5.13合约教程.md ├── 5.1账户类型与交易.md ├── 5.2ether转移.md ├── 5.3制定合约.md ├── 5.4编译合约.md ├── 5.5生成和部署合约.md ├── 5.6Gas和交易花费.md ├── 5.7与合约交互.md ├── 5.8合约信息(元数据).md ├── 5.9NatSpec.md ├── 5合约与交易.md └── README.md /0.1什么是以太坊.md: -------------------------------------------------------------------------------- 1 | # Welcome to the Frontier! 2 | Frontier是以太坊(Ethereum)网络第一个发布版, 当进入此未知领域,希望你可以测试和探索它。它有很多的危险,也会存在没有被发现的陷阱,也可能会有肆虐的海盗等待攻击你,但是也蕴含着很多的机会 3 | 4 | ## 什么是以太坊 5 | 和其他先进系统一样,以太坊对不同的人意味着不同的东西,在阅读本节时,有些地方不会引起你的共鸣或者让你感觉没有意思。没关系,直接跳到下一章节,希望可以给你更多启发。假如你读到本章节的末尾还非常迷惑,你可以到相关的论坛留言询问。 6 | 7 | >“很可能...一台机器足以解决整个[世界]的所有问题 - - 达尔文爵士,1946年 8 | 9 | 从技术意义上来说,以太坊是一个世界计算机(world computer)。在技​​术意义上,艾瑟利亚是一个“世界电脑”。回到大型机的时代,可能大概是一样快,以太坊可以被看作是一个全世界可以使用的一台电脑。理论上它只有一个处理器(没有多线程或并行执行),但是需要尽可能多的内存。任何人都可以将程序上传到这个Ethereum World Computer上,任何人都可以要求执行已上传的程序。但这并不意味着任何人都可以要求任何程序做任何事情。相反,程序的作者可以指定任何人的请求,但自己被忽略。例如,在强烈的意义上,每个程序都有自己的永久存储空间,在执行之间持续存在。此外,只要存在需求,Ethereum World Computer将永远在那里,他不可能被关闭。 10 | 你可能会问:“为什么会有人使用这样的系统?” 有很多原因。其主要原因是因为它使您想要做的事情成本更低,也更容易。这个说法需要细分一些,这是以下段落所探讨的。 11 | 12 | ## 网络服务平台 13 | >“技术给了我们缩短时间和距离的设施 - 电报和电缆,电话,广播和其他部分。” - Emily Greene Balch 14 | 15 | 在更实际的意义上,Ethereum是一个确保计算的互联网服务平台。不仅如此,作为一个平台,它提供了一些对开发人员非常有用的整体功能: 16 | * 用户认证,通过密码签名的无缝集成 17 | * 完全可定制的支付逻辑,轻松创建自己的支付系统,而不用依赖第三方 18 | * 100%抵抗ddos,通过完全分散的基于Blockchain的平台来保证 19 | * 不用担心存储:无需安装安全的数据库; Ethereum可以为您提供你想要的足够多的存储空间 20 | * 强大的互操作性:Ethereum生态系统中的所有内容都可以与其他所有内容进行轻松的交互,从声誉到自定义货币 21 | * 服务器免费区域:您的整个应用程序可以部署在blockchain上,这意味着不需要建立或维护服务器; 让您的用户支付使用你服务的费用。 22 | 23 | 特别是二十年来,我们看到,服务和基础设施的发展加速发展,主要是互联网,使得作为一个团队工作或运营企业的开销变得更加简单和便宜。比如,eBay,Drivy和Airbnb已经让开了一个商店,租车公司或酒店更容易。这些平台让人们可以快速实现自己的想法,只要他们想提供的服务适合平台提供的模板。在Ethereum之外,如果那些已经存在的平台不符合您的需求,创建新平台的成本是很高昂的。Ethereum可以看做是平台的平台,它允许人们很容易创建基础架构,以便在互联网上创建新的服务。此外,任何在Ethereum上创建的基础设施都与其他所有人的创作一致,因此可以有保障和无缝的方式与其他平台进行互动。重要的是,由于没有一家公司或者实体控制Ethereum,运行基础架构的成本不一定包括任何利润率,所以我们可能会看到更低的成本。 24 | 25 | 随着Mix IDE和Mist browser的到来,Ethereum作为互联网服务的部署平台的功能会更明确。然而,此章节的关键信息是,Ethereum准备破坏金融业等供应链复杂的行业。 26 | 27 | ## 选择社会契约 28 | >“这是组织的时代” -Theodore Roosevelt, 1912 29 | 30 | 在一个更抽象的层面上来说,它是一个可以使智能组织,或者称作是实体群,为了特殊原因能够共同工作的设施。在最简单的情况下,两个人在一起来实现贸易。最终,Ethereum可以用来来使国家运转。在那里有一些人想组织婴儿游乐场,影视制作集团,讨论组,公共房屋等,他们都必须决定他们一起经营的规则。可以说,更艰巨的任务是如何实施和强迫执行规则,特别是考虑到人类的性格,能力和动机的复杂性。换句话说,你如何阻止Jo偷取他人的相机设备,或者是阻止Dave不履行照顾孩子的行为?Ethereum提供了一个可以定义规则的平台,并且随着技术的进步越来越多地看到强制执行。例如,相机一直监听blockchain,并且仅记录影视制作集团的DApp是否批准Jo的访问码。 31 | 32 | 众筹是提升组织工具的关键范例。它提供了几个非常重要的功能:个人为某一特定事业(在这种情况下为一个人或一群人提供现金)合作的方式,以及个人与潜在的大公司有意义的交互机制(如一个游戏工作室)。第一点从上一段内容可以获得,但第二点也是令人印象深刻的,因为一般来说,个人只能根据组织的条款与大型组织进行沟通,这往往默认为“忽视”,就像你忽略你皮肤上的细菌一样。就这样,你可能对众筹者收了你的钱后,使用不当且低效的行为很不高兴。但是,很难让运营公司代表您对众筹者采取行动。毕竟,众筹的服务提供商很可能是一家大公司。如果不想让你做,那么就不会有你可以与他沟通的统一机制。Ethereum可以帮助你定义融资里程碑或条件来确定支付的总金额,然后为您执行这些条件。随着时间的推移,我们将以更加有创意的方式让Ethereum与现实世界进行交互,并且拓展Ethereum检测里程碑是否被完成的能力,此能力不局限于那种明显的“30%的人群资助项目(按价值)表示已经通过了里程碑“的条件。 33 | 34 | ## 去中心化革命的一部分 35 | >“无论你投票给谁,政府最终总是参与进来” - Bonzo Dog Doo-Dah 1992 36 | 37 | 在哲学上,这是重新下放互联网的下一步。在去中心化制度中,任何人都可以单方面加入和参与进来,所有参与者都参与它的运行和维护,任何参与者可以单方面离开,而系统不受影响。去中心化制度中,没有任何实体可以阻止其他人的参与或者任意审查系统中的内容或使用权。互联网本来是被设计为去中心化的,但是我们使用它的方式越来越集中,直到审查机构和被我们接受和期待。由Satoshi Nakamoto推出的Blockchain技术与概念验证实现简单的价值转移系统(称为比特币)代表了我们拥有的最好的数字系统(在互联网本身之后),用于管理多用户交互,而不需要集中协调或监督。实际上,一个去中心化的制度是它执行规则的权力(例如,“在比特币中你只能花一点钱”,或者在Ethereum中对你的智能合约执行你编写的任何规则),所以参与者可以相信他们希望执行的规则将是没有任何腐败,贿赂,裙带关系,政治偏见,排外,例外,人为监督或缺乏工作人员的危险。 38 | 通过以完全对等的方式进入中立可执行的协议,Ethereum允许人们安全地互动。现在,必须记住的是,Ethereum只能在自己的数字范围内执行, 它并没有在其领域之外消除外界权威对争端裁决的需要---“对方在Ethereum中说自己不会,但是当面又强迫我”对Ethereum来说是无意义的,但存在于其他地方的其他规则可以覆盖到这一点---但是,Ethereum做的是允许我们把这个边界推动到数字领域可以覆盖的地方。 39 | 40 | ## 总结 41 | Gavin Wood将Ethereum的描述作为非本地化单例的可编程数据结构的集合。这意味着什么取决于你来自哪里,但无论你身在何处,与Ethereum同在的日子会更好 42 | -------------------------------------------------------------------------------- /1.1.1Linux.md: -------------------------------------------------------------------------------- 1 | ## Linux安装选项 2 | ## Debian / Ubuntu 3 | ## 从PPA安装 4 | 5 | 想获取最新开发的进展,ppa:ethereum/ethereum和ppa:ethereum/ethereum-dev都是必须的。如果你想要最后一个PoC稳定版本,只添加第一个 6 | 7 | sudo apt-get install software-properties-common 8 | sudo add-apt-repository -y ppa:ethereum/ethereum 9 | sudo add-apt-repository -y ppa:ethereum/ethereum-dev 10 | sudo apt-get update 11 | sudo apt-get install ethereum 12 | 13 | 安装完成后,运行`geth account new`在您的节点上创建一个帐户。 14 | 您现在应该能够运行`geth`并连接到网络。 15 | 使用`geth --help`检查不同的选项和命令 16 | 假如你不想安装其他实用程序(`bootnode,evm,disasm,rlpdump,ethtest`),您也可以使用`apt-get install geth`只安装`geth CLI` 。 17 | 18 | ## 从源文件构建 19 | ### 构建Geth(命令行客户端) 20 | 21 | 将仓库clone到您选择的目录中: 22 | 23 | git clone https://github.com/ethereum/go-ethereum 24 | 25 | 如果您还没有安装Go(v1.4)的最新版本: 26 | 27 | [参见说明](https://github.com/ethereum/go-ethereum/wiki/Installing-Go#ubuntu-1404) 28 | 29 | 构建 `geth`需要安装一些外部库: 30 | 31 | sudo apt-get install -y build-essential libgmp3-dev golang 32 | 33 | 最后,`geth`使用以下命令构建程序。 34 | 35 | cd go-ethereum 36 | make geth 37 | 38 | 您现在可以运行`build/bin/geth`启动您的节点。 39 | 40 | ## Arch 41 | ## 从源文件安装 42 | 安装依赖关系 43 | 44 | pacman -S git go gcc gmp 45 | 46 | 下载并构建geth 47 | 48 | git clone https://github.com/ethereum/go-ethereum 49 | cd go-ethereum 50 | make geth 51 | -------------------------------------------------------------------------------- /1.1.2Mac.md: -------------------------------------------------------------------------------- 1 | ## Mac安装选项 2 | ### 用Homebrew安装 3 | 4 | 到目前为止,最简单的安装方法是使用我们的Homebrew tap。如果没有[Homebrew](https://brew.sh/),请先安装。 5 | 然后运行以下命令添加点击并安装`geth`: 6 | 7 | brew tap ethereum/ethereum 8 | brew install ethereum 9 | 10 | 您可以通过运行`--devel`以下方式安装开发分支: 11 | 12 | brew install ethereum --devel 13 | 14 | 安装完成后,运行`geth account new`在您的节点上创建一个帐户。 15 | 您现在应该能够运行`geth`并连接到网络。 16 | 使用`geth --help`检查不同的选项和命令 17 | 有关选项和修补程序,请参阅:https://github.com/ethereum/homebrew-ethereum 18 | ## 从源文件构建 19 | ### 建立Geth(命令行客户端) 20 | 21 | 将仓库clone到您选择的目录中: 22 | 23 | git clone https://github.com/ethereum/go-ethereum 24 | 25 | 构建 `geth`需要安装一些外部库: 26 | 27 | * [GMP](https://gmplib.org/) 28 | * [Go](https://golang.org/) 29 | 30 | 31 | brew install gmp go 32 | 33 | 最后,`geth`使用以下命令构建程序 34 | 35 | cd go-ethereum 36 | make geth 37 | 38 | 您现在可以运行`build/bin/geth`启动您的节点。 39 | -------------------------------------------------------------------------------- /1.1.3Windows.md: -------------------------------------------------------------------------------- 1 | # Windows安装指南 2 | ## 从Chocolatey安装 3 | 对于master分支: 4 | 5 | choco install geth-stable 6 | 7 | 有关更多信息,请参阅https://chocolatey.org/packages/geth-stable 8 | 9 | 对于develop分支: 10 | 11 | choco install geth-latest 12 | 13 | 有关更多信息,请参阅https://chocolatey.org/packages/geth-latest 14 | 15 | ## 从源文件构建 16 | 17 | 1. 从http://git-scm.com/downloads 下载安装Git 18 | 2. 从https://storage.googleapis.com/golang/go1.4.2.windows-amd64.msi 下载安装Golang 19 | 3. 从http://win-builds.org/1.5.0/win-builds-1.5.0.exe 下载winbuilds,安装到c:\winbuilds 20 | 4. 在此处运行win。删除像QT和GTK这样不需要的大型依赖关系是安全的。应确定依赖关系的确切列表 21 | 5. 设置环境路径 22 | - 添加`GOROOT`指向`c:\go,GOPATH`指向`c:\godev`(你可以自由挑选这些路径) 23 | - 设置`PATH`为`%PATH%;%GOROOT%\bin;%GOPATH%\bin;c:\winbuilds\bin` 24 | 25 | 6. 打开终端并先安装godep:`go get -u github.com/tools/godep` 26 | 7. 打开终端并下载go-elhereum `go get -d -u github.com/ethereum/go-ethereum` 27 | 8. 尝试用go dep构建ethereum,切换至`c:\godev\src\github.com\ethereum\go-ethereum\cmd\geth`,然后运行`git checkout develop && godep go install` 28 | 29 | 如果你想绕过`godep go install`使用其他分支构建`go install`,请手动检查依赖关系。 30 | 31 | ## 在Cygwin环境中使用Powershell脚本构建 32 | 33 | 警告:此安装方法目前无法正确链接。给出消息“ld:找不到-lmingwex”和“ld:找不到-lmingw32” 34 | 35 | #REQUIRES -Version 3.0 36 | # Set local directory paths 37 | $basedir = $env:USERPROFILE 38 | $downloaddir = "$basedir\Downloads" 39 | 40 | # Set Go variables 41 | $golangroot = "$basedir\golang" 42 | $gosrcroot = "$basedir\go" 43 | $golangdl = "https://storage.googleapis.com/golang/" 44 | 45 | # Set cygwin variables 46 | $cygwinroot = "$basedir\cygwin" 47 | $cygwinpackages = "gcc-g++,binutils,make,git,gmp,libgmp10,libgmp-devel" 48 | $cygwinmirror = "http://cygwin.mirrorcatalogs.com" 49 | $cygwindl = "https://cygwin.com/" 50 | 51 | # Finalize paths based on processor architecture 52 | if ($ENV:PROCESSOR_ARCHITECTURE -eq "AMD64") { 53 | $golangdl = $golangdl + "go1.5.1.windows-amd64.zip" 54 | $cygwindl = $cygwindl + "setup-x86_64.exe" 55 | } else { 56 | $golangdl = $golangdl + "go1.5.1.windows-386.zip" 57 | $cygwindl = $cygwindl + "setup-x86.exe" 58 | } 59 | 60 | # Download dependencies 61 | Invoke-WebRequest $cygwindl -UseBasicParsing -OutFile "$downloaddir\cygwin-setup.exe" 62 | Invoke-WebRequest $golangdl -UseBasicParsing -OutFile "$downloaddir\golang.zip" 63 | 64 | # Install Cygwin & dependencies 65 | Invoke-Expression "$downloaddir\cygwin-setup.exe --root $cygwinroot --site $cygwinmirror --no-admin --quiet-mode --packages=$cygwinpackages" 66 | # Install Golang 67 | Add-Type -AssemblyName System.IO.Compression.FileSystem 68 | [System.IO.Compression.ZipFile]::ExtractToDirectory("$downloaddir\golang.zip", $golangroot) 69 | 70 | # Set environment variables 71 | # Only works locally 72 | $env:GOROOT = "$golangroot\go" 73 | $env:GOPATH = $gosrcroot 74 | $env:PATH = "$env:PATH;$cygwinroot\bin;$golangroot\go\bin;$gosrcroot\bin" 75 | # Only works in new sessions 76 | [Environment]::SetEnvironmentVariable("GOROOT", $env:GOROOT, "User") 77 | [Environment]::SetEnvironmentVariable("GOPATH", $env:GOPATH, "User") 78 | [Environment]::SetEnvironmentVariable("PATH", $env:PATH, "User") 79 | 80 | 81 | # Download go-ethereum source 82 | go get github.com/tools/godep 83 | git clone https://github.com/ethereum/go-ethereum $env:GOPATH/src/github.com 84 | cd $env:GOPATH/src/github.com/ethereum/go-ethereum 85 | godep go install .\cmd\geth 86 | -------------------------------------------------------------------------------- /1.1.4Docker.md: -------------------------------------------------------------------------------- 1 | ## 在Docker上运行 2 | 我们在[DockerHub](https://hub.docker.com/)中保留了从develop分支构建的最新快照的Docker映像。首先运行: 3 | 4 | docker pull ethereum/client-go 5 | 6 | 启动一个节点: 7 | 8 | docker run -it -p 30303:30303 ethereum/client-go 9 | 10 | 要启动在端口**8545**上运行JSON-RPC接口的节点,请运行: 11 | 12 | docker run -it -p 8545:8545 -p 30303:30303 ethereum/client-go --rpc 13 | 14 | **警告:这将打开您的容器到外部呼叫** 15 | 16 | 要使用交互式JavaScript控制台,请运行: 17 | 18 | docker run -it -p 30303:30303 ethereum/client-go console 19 | -------------------------------------------------------------------------------- /1.1.5ARM.md: -------------------------------------------------------------------------------- 1 | ## ARM安装说明 2 | 3 | ARM上的Geth是使用交叉编译构建的。有关详细信息,请参阅[交叉编译Ethereum](https://github.com/ethereum/go-ethereum/wiki/Cross-compiling-Ethereum)。 4 | 5 | ## RasPi 2 6 | 7 | 1. 从主分支下载[预编译的二进制文件](https://build.ethdev.com/builds/ARM%20Go%20master%20branch/geth-ARM-latest.tar.bz2) 8 | 2. 将其复制到$PATH中的位置(即`/usr/bin/local`) 9 | 3. 运行`geth` 10 | 11 | 更多详情: https://github.com/ethereum/wiki/wiki/Raspberry-Pi-instructions 12 | -------------------------------------------------------------------------------- /1.1平台.md: -------------------------------------------------------------------------------- 1 | # 安装说明 2 | 请按照下面的相应链接查找平台的安装说明。 3 | * [Mac OS X安装说明](https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Mac) 4 | * [Windows安装说明](https://github.com/ethereum/go-ethereum/wiki/Installation-instructions-for-Windows) 5 | * Linux / Unix的安装说明 6 | - [Ubuntu](https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Ubuntu) 7 | - [Arch](https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Arch) 8 | - [FreeBSD](https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-FreeBSD) 9 | * [Raspberry Pi的设置](https://github.com/ethereum/wiki/wiki/Raspberry-Pi-instructions) 10 | - [ARM](https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-ARM) 11 | * [Docker的使用说明](https://github.com/ethereum/go-ethereum/wiki/Running-in-Docker) 12 | 13 | 您也可以使用单行脚本安装Geth。打开一个命令行或终端工具(如果您不确定如何做到这一点,请考虑等待更友好的版本)并粘贴以下命令: 14 | 15 | bash <(curl -L https://install-geth.ethereum.org) 16 | 17 | 该脚本将检测您的操作系统,并将尝试安装ethereum CLI。有关包管理器的更多选项,请查看操作系统相关的特定子部分. 18 | 更多链接: 19 | * [Compiled binaries on launchpad.net buildbot listings](https://launchpad.net/~ethereum) 20 | 21 | * [Ethereum buildbot](https://build.ethdev.com/) 22 | -------------------------------------------------------------------------------- /1.2备份和恢复.md: -------------------------------------------------------------------------------- 1 | #### **不要忘记你的密码并备份你的密码** 2 | 3 | # 备份和恢复 4 | 5 | ## 数据目录 6 | 7 | 一切`geth`持续保存的内容都被写入其数据目录(除了PoW Ethash DAG,见下面的注释)。默认的数据目录位置在不同平台是特定的: 8 | * 苹果电脑: `~/Library/Ethereum` 9 | * Linux: `~/.ethereum` 10 | * Windows: `%APPDATA%/Ethereum` 11 | 12 | 帐户存储在`keystore`子目录中。该目录的内容应该可以在节点,平台,实现(C ++,Go,Python)之间传输。 13 | 14 | 要配置数据目录的位置,`--datadir`可以指定参数。有关详细信息,请参阅[CLI选项](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)。 15 | 16 | 注:该Ethash DAG存储在`~/.ethash`键(Mac/Linux)或`~/AppData/Ethash`(Windows)中,以便它可以被所有客户端重用。您可以使用符号链接将其存储在不同的位置。 17 | 18 | ## 升级 19 | 20 | 有时内部数据库格式需要升级(例如,从0.9.20之前升级)。这可以使用以下命令运行(geth不应该运行): 21 | 22 | geth upgradedb 23 | 24 | ## 清理 25 | 26 | Geth的blockchain和状态数据库可以用以下命令行删除: 27 | 28 | geth removedb 29 | 30 | 这对于删除旧的链并同步到新的链很有用。它只影响可以在同步时重新创建的数据目录,并且不会触及密钥库。 31 | 32 | ## blockchain导入和导出 33 | 34 | 以二进制格式导出块链: 35 | 36 | geth export 37 | 38 | 或者您想随时间备份链的部分,可以指定第一个和最后一个块。例如,要备份第一个块: 39 | 40 | geth export 0 29999 41 | 42 | 请注意,备份部分链时,文件将被追加而不是截断。 43 | 导入二进制格式的blockchain: 44 | 45 | geth import 46 | 47 | 有关详细信息,请参阅https://github.com/ethereum/wiki/wiki/Blockchain-import-export 48 | 49 | 最后:不要**忘记你的密码并备份你的密码** 50 | -------------------------------------------------------------------------------- /1.3连接至网络.md: -------------------------------------------------------------------------------- 1 | # 连接至网络 2 | ## 如何找到对等节点(Peers) 3 | Geth不断尝试连接到网络上的其他节点,直到它找到peers。如果您在路由器上启用了UPnP,或者在面向Internet的服务器上运行其他方式,则它也将接受其他节点的连接。 4 | 5 | Geth通过称为发现协议的东西找到peers。在发现协议中,节点相互通信以了解网络上的其他节点。为了一开始就可以执行,geth使用一组引导节点,其被记录在源代码中。 6 | 7 | 想要在启动时更改bootnodes,请使用`--bootnodes`选项并按空格分隔节点。例如: 8 | 9 | geth --bootnodes "enode://pubkey1@ip1:port1 enode://pubkey2@ip2:port2 enode://pubkey3@ip3:port3" 10 | 11 | ## 连通的常见问题 12 | 13 | 有时你无法被连接到。最常见的原因如下: 14 | 15 | * 本地时间可能不正确。需要精确的时钟才能参与到Ethereum网络中。检查您的操作系统以了解如何重新同步您的时钟(例如`sudo ntpdate -s time.nist.gov`),因为即使快12秒也可能导致找不到对等体。 16 | * 一些防火墙配置可以防止UDP流量流失。您可以使用静态节点功能或`admin.addPeer()`在控制台上手动配置连接。 17 | 18 | 想要在没有发现协议的情况下启动geth,可以使用该`--nodiscover`参数。假如你正在运行一个测试节点或具有固定节点的实验测试网络,你会需要这个的。 19 | 20 | ## 检查连通性 21 | 要查看客户端在交互式控制台中连接多少个peer,该net模块有两个属性可以提供有关peer数量以及是否为监听节点的信息。 22 | 23 | > net.listening 24 | true 25 | > net.peerCount 26 | 4 27 | 28 | 要获取有关连接对等体的更多信息,如IP地址和端口号,支持的协议,请使`admin`对象的功能`peers()`。`admin.peers()`返回当前连接的对等体的列表。 29 | 30 | > admin.peers 31 | [{ 32 | ID: 'a4de274d3a159e10c2c9a68c326511236381b84c9ec52e72ad732eb0b2b1a2277938f78593cdbe734e6002bf23114d434a085d260514ab336d4acdc312db671b', 33 | Name: 'Geth/v0.9.14/linux/go1.4.2', 34 | Caps: 'eth/60', 35 | RemoteAddress: '5.9.150.40:30301', 36 | LocalAddress: '192.168.0.28:39219' 37 | }, { 38 | ID: 'a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c', 39 | Name: 'Geth/v0.9.15/linux/go1.4.2', 40 | Caps: 'eth/60', 41 | RemoteAddress: '52.16.188.185:30303', 42 | LocalAddress: '192.168.0.28:50995' 43 | }, { 44 | ID: 'f6ba1f1d9241d48138136ccf5baa6c2c8b008435a1c2bd009ca52fb8edbbc991eba36376beaee9d45f16d5dcbf2ed0bc23006c505d57ffcf70921bd94aa7a172', 45 | Name: 'pyethapp_dd52/v0.9.13/linux2/py2.7.9', 46 | Caps: 'eth/60, p2p/3', 47 | RemoteAddress: '144.76.62.101:30303', 48 | LocalAddress: '192.168.0.28:40454' 49 | }, { 50 | ID: 'f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0', 51 | Name: '++eth/Zeppelin/Rascal/v0.9.14/Release/Darwin/clang/int', 52 | Caps: 'eth/60, shh/2', 53 | RemoteAddress: '129.16.191.64:30303', 54 | LocalAddress: '192.168.0.28:39705' 55 | } ] 56 | 57 | 检查geth使用的端口,并找到您的enode URI,运行: 58 | 59 | > admin.nodeInfo 60 | { 61 | Name: 'Geth/v0.9.14/darwin/go1.4.2', 62 | NodeUrl: 'enode://3414c01c19aa75a34f2dbd2f8d0898dc79d6b219ad77f8155abf1a287ce2ba60f14998a3a98c0cf14915eabfdacf914a92b27a01769de18fa2d049dbf4c17694@[::]:30303', 63 | NodeID: '3414c01c19aa75a34f2dbd2f8d0898dc79d6b219ad77f8155abf1a287ce2ba60f14998a3a98c0cf14915eabfdacf914a92b27a01769de18fa2d049dbf4c17694', 64 | IP: '::', 65 | DiscPort: 30303, 66 | TCPPort: 30303, 67 | Td: '2044952618444', 68 | ListenAddr: '[::]:30303' 69 | } 70 | 71 | ## 自定义网络 72 | 73 | 有时您可能不需要连接到实时公用网络,您可以选择创建自己私有的testnet。如果您不需要测试外部合同,并且只需要测试该技术,这是非常有用的,因为您不必与其他矿工竞争,并且可以轻松地生成大量的测试以太来试验(可用非负数替换12345): 74 | 75 | geth -—networkid="12345" console 76 | 77 | 还可以通过提供--genesis标志从JSON文件中运行带有自定义生成块的geth 。原生JSON文件应具有以下格式: 78 | 79 | { 80 | "alloc": { 81 | "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { 82 | "balance": "1606938044258990275541962092341162602522202993782792835301376" 83 | }, 84 | "e6716f9544a56c530d868e4bfbacb172315bdead": { 85 | "balance": "1606938044258990275541962092341162602522202993782792835301376" 86 | }, 87 | ... 88 | }, 89 | "nonce": "0x000000000000002a", 90 | "difficulty": "0x020000", 91 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 92 | "coinbase": "0x0000000000000000000000000000000000000000", 93 | "timestamp": "0x00", 94 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 95 | "extraData": "0x", 96 | "gasLimit": "0x2fefd8" 97 | } 98 | 99 | 100 | ## 静态节点 101 | 102 | Geth还支持一个名为静态节点的功能,如果您有某些对等体您总是要连接到。静态节点在断开连接后会重新连接。您可以通过类似以下方式配置永久静态节点 `/static-nodes.json`: 103 | 104 | [ 105 | "enode://f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0@33.4.2.1:30303", 106 | "enode://pubkey@ip:port" 107 | ] 108 | 109 | 您还可以通过js控制台在运行时使用[admin.addPeer()](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console#addpeer)添加静态节点: 110 | 111 | admin.addPeer("enode://f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0@33.4.2.1:30303") 112 | 113 | 注意事项:控制台目前缺少删除peer,增加peer数量或者添加非静态peer,但不要不断尝试重新连接。 114 | -------------------------------------------------------------------------------- /1.4监控你的节点.md: -------------------------------------------------------------------------------- 1 | # 网络状态监控 2 | [Ethereum(集中式)网络状态监视器](https://stats.ethdev.com/)(有时称为“ETH-netstats”),是一个通过一组节点监控testnet / mainnet状态的、基于web的应用程序。 3 | 4 | ## 列举 5 | 6 | 要列出您的节点,您必须安装client-side information relay,一个节点模块。在这里给出在Ubuntu上工作说明(Mac OS X遵循相同的说明,但是可能不需要`sudo`)。其他平台有所不同(请确保还安装了`nodejs-legacy`,否则某些模块可能会失败)。 7 | clone git仓库,然后安装pm2: 8 | 9 | git clone https://github.com/cubedro/eth-net-intelligence-api 10 | cd eth-net-intelligence-api 11 | npm install 12 | sudo npm install -g pm2 13 | 14 | 编辑`app.json`文件为你的节点配置 15 | * 更改LISTENING_PORT右边的值为ethereum 监听端口(默认值:30303) 16 | * 更改INSTANCE_NAME右边的值为你想给你的节点起的任何名字 17 | * 更改CONTACT_DETAILS右边的值,如果您希望分享您的联系方式 18 | * 更改RPC_PORT右边的值为你的节点的rpc端口(对于cpp和go,默认为8545); 19 | * 更改WS_SECRET右边的值为secret(你必须从官方skype渠道获取) 20 | 21 | 最后运行该过程: 22 | `pm2 start app.json` 23 | 24 | 有几个命令可用: 25 | 26 | * `pm2 list` 显示进程状态; 27 | * `pm2 logs` 显示日志; 28 | * `pm2 gracefulReload node-app` 用于软重载 29 | * `pm2 stop node-app` 停止应用程序 30 | * `pm2 kill` 杀死守护进程。 31 | 32 | ## 更新 33 | 为了更新,您必须执行以下操作: 34 | 35 | * `git pull` 拉最新版本 36 | * `sudo npm update` 更新依赖关系 37 | * `pm2 gracefulReload node-app` 重新加载客户端 38 | 39 | *** 40 | 41 | ## 在新的Ubuntu上自动安装 42 | 43 | 获取并运行shell构建脚本。这将安装您需要的一切:开发分支中最新的ethereum -CLI(您可以选择eth或geth),node.js,npm和pm2。 44 | 45 | bash <(curl https://raw.githubusercontent.com/cubedro/eth-net-intelligence-api/master/bin/build.sh) 46 | 47 | ## 配置 48 | 修改processes.json来配置应用程序。请注意,您必须修改位于`./bin/processes.json`的备份processes.json文件(以便在更新时允许您设置env var而不被重写)。 49 | 50 | "env": 51 | { 52 | "NODE_ENV" : "production", // tell the client we're in production environment 53 | "RPC_HOST" : "localhost", // eth JSON-RPC host the default is 8545 54 | "RPC_PORT" : "8545", // eth JSON-RPC port 55 | "LISTENING_PORT" : "30303", // eth listening port (only used for display) 56 | "INSTANCE_NAME" : "", // whatever you wish to name your node 57 | "CONTACT_DETAILS" : "", // add your contact details here if you wish (email/skype) 58 | "WS_SERVER" : "wss://stats.ethdev.com", // path to eth-netstats WebSockets api server 59 | "WS_SECRET" : "", // WebSockets api server secret used for login 60 | } 61 | 62 | ## 运行 63 | 使用pm2来运行: 64 | 65 | cd ~/bin 66 | pm2 start processes.json 67 | 68 | ethereum (eth or geth)运行时,rpc 必须先处于可用状态 69 | 70 | geth --rpc 71 | 72 | 如果没有指定,rpc在geth下的默认端口为8545 73 | 74 | ## 更新 75 | 使用以下的命令来更新API客户端 76 | 77 | ~/bin/www/bin/update.sh 78 | 79 | 它将停止当前的netstats客户端进程,自动检测您的ethereum实现和版本,将其更新到最新的开发版本,升级netstats客户端并重新加载进程。 80 | -------------------------------------------------------------------------------- /1.5设置集群.md: -------------------------------------------------------------------------------- 1 | # 设置集群(cluster) 2 | 3 | 4 | 本章节将介绍如何设置本地节点群集,如何使其成为私有的,以及如何使你在eth-netstat网络上的节点协同工作来监控应用程序。作为网络集成测试(与网络/blockchain同步/消息传播等相关的问题,DAPP开发人员测试多块和多用户场景)的后端,完全可供你的ethereum网络是非常有用的。 5 | 6 | 我们假设您可以通过[安装指南](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)构建`geth` 7 | ## 设置多个节点 8 | 9 | 为了在本地运行多个ethereum节点,您必须确保: 10 | 11 | * 每个实例都有一个单独的数据目录(`--datadir`) 12 | * 每个实例运行在不同的端口(eth和rpc)(`--port` 和 `--rpcport`) 13 | * 在集群的情况下,实例必须清楚对方的存在 14 | * ipc端点是唯一的,或ipc接口被禁用(`--ipcpath` 或者 `--ipcdisable`) 15 | 16 | 启动第一个节点(端口暴露出来和禁用ipc接口) 17 | 18 | geth --datadir="/tmp/eth/60/01" -verbosity 6 --ipcdisable --port 30301 --rpcport 8101 console 2>> /tmp/eth/60/01.log 19 | 20 | 我们使用console启动节点,以便我们可以获取enode url,例如: 21 | 22 | > admin.nodeInfo.NodeUrl 23 | enode://8c544b4a07da02a9ee024def6f3ba24b2747272b64e16ec5dd6b17b55992f8980b77938155169d9d33807e501729ecb42f5c0a61018898c32799ced152e9f0d7@9[::]:30301 24 | 25 | `[::]`将被解析为localhost(`127.0.0.1`)。如果您的节点在本地网络上,请检查每台主机,并使用`ifconfig`(在Linux和MacOS上)找到您的ip : 26 | 27 | $ ifconfig|grep netmask|awk '{print $2}' 28 | 127.0.0.1 29 | 192.168.1.97 30 | 31 | 如果你的peers不在本地网络上,则需要知道你的外部IP地址(使用服务)来构造enode url。 32 | 33 | 现在可以启动第二个节点: 34 | 35 | geth --datadir="/tmp/eth/60/02" --verbosity 6 --ipcdisable --port 30302 --rpcport 8102 console 2>> /tmp/eth/60/02.log 36 | 37 | 如果要将此实例连接到先前启动的节点,则可以从console使用`admin.addPeer(enodeUrlOfFirstInstance)`将其添加为peer。 38 | 39 | 您可以在geth控制台来测试连接: 40 | 41 | > net.listening 42 | true 43 | > net.peerCount 44 | 1 45 | > admin.peers 46 | ... 47 | Local cluster 48 | 49 | ## 本地集群 50 | 51 | 作为上述的扩展,您可以轻松地生成本地的节点群集。它也可以被构建成脚本,包括挖掘所需的帐户创建。请参阅gethcluster.sh脚本以及README中的用法和示例。 52 | 53 | ## 私有网络 54 | 55 | 如果其节点没有连接到主网络节点,那么ethereum网络就是私有网络。在这种情况下,私有只意味着保守或隔离,而不是保护或安全。由于节点之间的连接仅在peers具有相同协议版本和网络ID的情况下才有效,因此可以通过将其中的任何一个设置为非默认值来有效地隔离网络。我们建议为此使用`networkid`命令行选项。它的参数是整数,主网络的id为1(默认值)。因此,如果您提供与主网络不同的自定义网络ID,您的节点将不会连接到其他节点并形成私有网络。 56 | 57 | ## 监控节点 58 | 59 | [本页](https://github.com/ethereum/wiki/wiki/Network-Status)介绍如何使用[Ethereum(集中式)网络状态监视器(有时称为”eth-netstats“)](http://stats.ethdev.com/)来监视节点。 60 | 61 | [本页](https://github.com/ethereum/go-ethereum/wiki/Setting-up-monitoring-on-local-cluster)或[README](https://github.com/ethersphere/eth-utils) 介绍如何为(私有或公共)本地集群设置自己的监控服务。 62 | -------------------------------------------------------------------------------- /1安装并运行节点.md: -------------------------------------------------------------------------------- 1 | ## 获取Geth 2 | Frontier工具被称为Geth("to go"古英语的第三人称单数)。考虑到geth由[go](https://golang.org/)语言编写,这个名称十分适合。Geth是一个多用途命令行工具,可以操作使用Go实现的完整的Ethereum节点。它提供三个接口:[命令行子命令和选项](https://ethereum.gitbooks.io/frontier-guide/content/Command-Line-Options/),Json-rpc服务器和交互式控制台。 3 | 为了安装Geth,打开一个命令行或终端工具(如果你不确定如何做到这一点,请考虑等待更友好的版本),然后粘贴以下命令: 4 | 5 | bash <(curl https://install-geth.ethereum.org) 6 | 该脚本将检测您的操作系统,并将尝试安装ethereum CLI。有关包管理器的更多选项,请查看操作系统相关的特定子部分。 7 | 8 | ## 第一次运行 9 | 本指南的目的很简单,我们将专注于介绍交互式控制台和一个JavaScript环境。控制台的使用会在以后的章节中持续展现,提供了一个强大而灵活的使用客户端的方式。您可以使用向上和向下箭头键(如标准命令行)展示您的命令历史记录。准备开始,请先在您的终端上输入下面的代码 10 | 11 | geth console 12 | 13 | 一旦geth完全启动,您应该会看到一个`>`提示,让您知道控制台已准备就绪。假如要退出,请输入`exit`提示并点击`[enter]`键。 14 | 15 | ## 使用stderr 16 | 可以记录或重定向控制台的输出: 17 | 18 | geth console 2>>geth.log 19 | 20 | 使用标准工具,可以在单独的窗口中监视日志: 21 | 22 | tail -f geth.log 23 | 24 | 或者,您也可以使用交互式控制台运行一个终端,另外还可以直接使用日志输出。 25 | 1. 打开两个终端 26 | 2. 在第二终端输入`tty`。输出类似这样的`/dev/pts/13` 27 | 3. 在您的主要终端,输入: `geth console 2>> /dev/pts/13` 28 | 29 | 这将允许您监视您的节点,而不会把交互式控制台搞混了。 30 | -------------------------------------------------------------------------------- /2.1创建账户.md: -------------------------------------------------------------------------------- 1 | # 创建帐户 2 | ## 创建一个新帐户 3 | 4 | `geth account new` 5 | 6 | 创建一个新帐户并打印地址。 7 | 8 | 在Console上,使用: 9 | 10 | > personal.newAccount("passphrase") 11 | 12 | 该帐户以加密格式保存。您必须记住这个密码以将来解锁您的帐户。 13 | 对于非交互式使用,可以使用`--password`标志指定密码: 14 | 15 | geth --password account new 16 | 17 | 请注意,这仅用于测试,将密码保存到文件或以任何其他方式暴露是一个坏主意。 18 | 19 | ## 通过导入私钥创建帐户 20 | 21 | geth account import 22 | 23 | 从中导入未加密的私钥,创建一个新帐户并打印地址。 24 | 假设密钥文件包含未加密的私钥,其是被编码成十六进制的规范EC原始字节。 25 | 26 | 该帐户以加密格式保存,系统将提示您输入密码。 27 | 28 | 您将来必须记住这个密码以解锁您的帐户。 29 | 30 | 对于非交互式使用,可以使用`--password`标志指定密码: 31 | 32 | geth --password account import 33 | 34 | **注意**:由于您可以将加密帐户直接复制到另一个ethereum实例,因此在节点之间传输帐户时不需要此导入/导出机制。 35 | 36 | **警告**:将密钥复制到现有节点的密钥库中时,您使用的帐户顺序可能会更改。因此,您确保不依赖于帐户顺序或双重检查并更新脚本中使用的索引。 37 | 38 | **警告**: 如果您使用带有密码文件的密码标志,最好确保除了您以外的任何人都不可读或甚至可以列出该文件。你可以这样做: 39 | 40 | touch /path/to/password 41 | chmod 700 /path/to/password 42 | cat > /path/to/password 43 | >I type my pass here^D 44 | 45 | ## 更新现有账户 46 | 47 | 您可以在命令行上使用帐户地址或索引作为参数的更新子命令来`update`现有账户。 48 | 49 | geth account update b0047c606f3af7392e073ed13253f8f4710b08b6 50 | geth account update 2 51 | 52 | 该帐户以加密格式保存在最新版本中,系统将提示您输入密码以解锁帐户,另一个用于保存更新的文件。使用相同的命令把采用废弃格式的帐户迁移到最新格式或更改帐户的密码。 53 | 54 | 对于非交互式使用,可以使用`--password`标志指定密码: 55 | 56 | geth --password account new 57 | 58 | 由于只能提供一个密码,只能执行格式更新,只有更改密码才能交互。 59 | 60 | **注意**:帐户更新有一个副作用,您的帐户顺序更改。 61 | 62 | 成功更新后,同一个键的所有旧格式/版本将被删除! 63 | -------------------------------------------------------------------------------- /2.2导入你的presale钱包.md: -------------------------------------------------------------------------------- 1 | 2 | ## 导入你的presale钱包 3 | 导入你的presale钱包非常容易,假如你还记得你的密码,你可以: 4 | 5 | geth wallet import /path/to/my/presale.wallet 6 | 7 | 将提示输入您的密码并导入您的以太网presale帐户。它还可以使用非交互方式,即以密码文件作为参数的`--password`选项,密码文件中包含明文的钱包密码。 8 | -------------------------------------------------------------------------------- /2.3列出账户和检查余额.md: -------------------------------------------------------------------------------- 1 | ## 列出账户和检查余额 2 | 3 | ### 列出你现有的账户 4 | 在命令行输入: 5 | 6 | $ geth account list 7 | Account #0: {d1ade25ccd3d550a7eb532ac759cac7be09c2719} 8 | Account #1: {da65665fc30803cb1fb7e6d86691e20b1826dee0} 9 | Account #2: {e470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32} 10 | Account #3: {f4dd5c3794f1fd0cdc0327a83aa472609c806e99} 11 | 12 | 会列出你所创建的所有账户 13 | 14 | **注意**: 假如你从其他的节点拷贝密钥文件过来,这个顺序会发生改变。所以您确保不依靠索引,或确保您复制了您在脚本中检查和更新帐户索引的密钥。 15 | 16 | 使用控制台: 17 | 18 | > eth.accounts 19 | ['0x407d73d8a49eeb85d32cf465507dd71d507100c1'] 20 | 21 | 或者使用RPC: 22 | 23 | # Request 24 | $ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1} http://127.0.0.1:8545' 25 | 26 | # Result 27 | { 28 | "id":1, 29 | "jsonrpc": "2.0", 30 | "result": ["0x407d73d8a49eeb85d32cf465507dd71d507100c1"] 31 | } 32 | 33 | 如果您想以非交互方式使用帐户,则需要解除锁定。您可以在命令行上执行此操作,该`--unlock`选项将空白分隔的帐户列表(十六进制或索引)作为参数,以便您可以以一种会话方式解锁帐户。如果您想通过RPC从Dapps使用您的帐户,这是非常有用的。`--unlock`将解锁第一个帐户。当您以编程方式创建帐户时,您不需要知道实际的帐户来解锁它,这是非常有用的. 34 | 35 | 解锁一个帐户: 36 | 37 | geth --password <(echo this is not secret!) account new 38 | geth --password <(echo this is not secret!) --unlock primary --rpccorsdomain localhost --verbosity 6 2>> geth.log 39 | 40 | 您可以使用整数索引替代帐户地址,它指的是帐户列表中的地址位置(并且对应于创建顺序)。 41 | 42 | 命令行允许您解锁多个帐户。在这种情况下,解锁的参数是空白分隔的帐户地址或索引列表。 43 | 44 | geth --unlock "0x407d73d8a49eeb85d32cf465507dd71d507100c1 0 5 e470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32" 45 | 46 | 如果使用这种非交互式结构,您的密码文件将需要包含相关帐户的相应密码,每行一个。 47 | 48 | 您也可以在控制台上解锁帐户(一次一个) 49 | 50 | personal.unlockAccount(address, "password") 51 | 52 | Note that we do NOT recommend using the password argument here, since the console history is logged, so you may compromise your account. You have been warned. 53 | 54 | **注意**: 我们 **不建议** 在这儿使用密码作为参数,,因为Console会保存历史记录,这样会危及你的账户,这点我们已经警告过了。 55 | 56 | ## 检查账户余额 57 | 58 | 检查你以太坊的账户余额: 59 | 60 | > web3.fromWei(eth.getBalance(eth.coinbase), "ether") 61 | 6.5 62 | 63 | 使用JavaScript方法打印所有的余额: 64 | 65 | function checkAllBalances() { 66 | var i =0; 67 | eth.accounts.forEach( function(e){ 68 | console.log(" eth.accounts["+i+"]: " + e + " \tbalance: " + web3.fromWei(eth.getBalance(e), "ether") + " ether"); 69 | i++; 70 | }) 71 | }; 72 | 73 | 可以这样调用: 74 | 75 | > checkAllBalances(); 76 | eth.accounts[0]: 0xd1ade25ccd3d550a7eb532ac759cac7be09c2719 balance: 63.11848 ether 77 | eth.accounts[1]: 0xda65665fc30803cb1fb7e6d86691e20b1826dee0 balance: 0 ether 78 | eth.accounts[2]: 0xe470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32 balance: 1 ether 79 | eth.accounts[3]: 0xf4dd5c3794f1fd0cdc0327a83aa472609c806e99 balance: 6 ether 80 | 81 | 由于这个功能在geth重启后会消失,把常用的方法记录下来以便以后调用。[loadScript](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console#loadscript)使得这样做很容易。 82 | 83 | 首先把checkAllBalances()保存至电脑上的一个文件中。例如: `/Users/username/gethload.js`。接着从交互式控制台上导入文件: 84 | > loadScript("/Users/username/gethload.js") 85 | true 86 | 87 | 该文件将修改您的JavaScript环境,就像您手动键入命令一样。请随意试验! 88 | -------------------------------------------------------------------------------- /2.4发送以太.md: -------------------------------------------------------------------------------- 1 | ## 发送以太 2 | 3 | 使用控Console发送ether的简单事务的基本方法如下: 4 | 5 | > eth.sendTransaction({from:sender, to:receiver, value: amount}) 6 | 7 | 使用内置的JavaScript,您可以轻松设置变量来保存这些值。例如: 8 | > var sender = eth.accounts[0]; 9 | > var receiver = eth.accounts[1]; 10 | > var amount = web3.toWei(0.01, "ether") 11 | 12 | 或者,您可以在一行中组合操作进行交易: 13 | 14 | > eth.sendTransaction({from:eth.coinbase, to:eth.accounts[1], value: web3.toWei(0.05, "ether")}) 15 | Please unlock account d1ade25ccd3d550a7eb532ac759cac7be09c2719. 16 | Passphrase: 17 | Account is now unlocked for this session. 18 | '0xeeb66b211e7d9be55232ed70c2ebb1bcc5d5fd9ed01d876fac5cff45b5bf8bf4' 19 | 20 | 由此产生的交易是 `0xeeb66b211e7d9be55232ed70c2ebb1bcc5d5fd9ed01d876fac5cff45b5bf8bf4` 21 | 22 | 如果密码不正确,您将会收到错误: 23 | 24 | `error: could not unlock sender account` 25 | -------------------------------------------------------------------------------- /2.管理账户.md: -------------------------------------------------------------------------------- 1 | # 管理账户 2 | **警告**:记住你的密码 3 | 4 | 假如你忘记了加密账户的密码,那你将无法使用账户 5 | 重申:没有密码就无法使用账户,没有“忘记密码”的选项,不要忘记这点 6 | 7 | **注意**:在0.9.36中,密钥文件命名约定已更改。本文档旨在反映Frontier release版本所使用帐户的准确信息。 8 | 9 | ethereum CLI通过`account`子命令提供了账户管理功能 10 | 11 | account command [arguments...] 12 | 13 | 管理帐户功能可让您创建新帐户,列出所有现有帐户,将私钥导入新帐户,迁移到最新密钥格式并更改密码。 14 | 当您被提示输入密码,或者处于使用给定的密码文件提供密码的非交互模式时,它支持交互模式。非交互模式仅用于在测试网络或已知安全环境中进行脚本化使用。 15 | 16 | 确保您记住创建新帐户(使用新的,更新或导入)时所使用的密码。没有它,您无法解锁您的帐户。 17 | 请注意,**不** 支持以未加密格式导出密钥。 18 | 19 | 密钥存储在`/keystore`。确保你经常备份你的钥匙!有关详细信息,请参阅[DATADIR备份和还原](https://github.com/ethereum/go-ethereum/wiki/Backup-&-restore)。关键文件的最新格式是:`UTC---
`。列出账户时的顺序是按字母排序,但是作为时间戳格式的结果,账户实际上是创建顺序排序的。 20 | 可以安全地在ethereum节点之间传输整个目录或其中的各个键。请注意,如果您从其他节点向您的节点添加密钥,则帐户顺序可能会改变。因此,请确保您不要依赖或更改脚本或代码段中的索引。 21 | 22 | 最后重申:**不要忘记你的密码** 23 | 24 | SUBCOMMANDS: 25 | 26 | list print account addresses 27 | new create a new account 28 | update update an existing account 29 | import import a private key into a new account 30 | 31 | 你可以通过`geth account help `获取更多子命令信息,你也可以通过[Javascript Console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console)管理账户。 32 | 33 | # 例子 34 | ## 交互使用 35 | 36 | ### 创建一个账户 37 | $ geth account new 38 | Your new account is locked with a password. Please give a password. Do not forget this password. 39 | Passphrase: 40 | Repeat Passphrase: 41 | Address: {168bc315a2ee09042d83d7c5811b533620531f67} 42 | 43 | ### 列出账户 44 | $ geth account list 45 | Account #0: {a94f5374fce5edbc8e2a8697c15331677e6ebf0b} 46 | Account #1: {c385233b188811c9f355d4caec14df86d6248235} 47 | Account #2: {7f444580bfef4b9bc7e14eb7fb2a029336b07c9d} 48 | 49 | ### 导入私钥 50 | $ geth --datadir /someOtherEthDataDir account import ./key.prv 51 | The new account will be encrypted with a passphrase. 52 | Please enter a passphrase now. 53 | Passphrase: 54 | Repeat Passphrase: 55 | Address: {7f444580bfef4b9bc7e14eb7fb2a029336b07c9d} 56 | 57 | ### 账户升级 58 | $ geth account update a94f5374fce5edbc8e2a8697c15331677e6ebf0b 59 | Unlocking account a94f5374fce5edbc8e2a8697c15331677e6ebf0b | Attempt 1/3 60 | Passphrase: 61 | 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b 62 | Account 'a94f5374fce5edbc8e2a8697c15331677e6ebf0b' unlocked. 63 | Please give a new password. Do not forget this password. 64 | Passphrase: 65 | Repeat Passphrase: 66 | 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b 67 | 68 | ## 非交互使用 69 | 你提供一个明文密码文件作为`--password`标志的参数。文件中的数据由密码的原始字符组成,后跟单个换行符。 70 | 71 | **注意**:不建议直接提供密码作为命令行的一部分,但您可以随时使用shell这样取巧的方法来绕过此限制。 72 | 73 | $ geth --password /path/to/password account new 74 | 75 | $ geth --password /path/to/password account update b0047c606f3af7392e073ed13253f8f4710b08b6 76 | 77 | $ geth account list 78 | 79 | $ geth --datadir /someOtherEthDataDir --password /path/to/anotherpassword account import ./key.prv 80 | -------------------------------------------------------------------------------- /3.1介绍.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | 采矿(mining)这个词起源于类比黄金的加密货币。金或者其他的贵金属是稀缺的,数字令牌也是如此,而增加总量的唯一方法是通过采矿。这在Ethereum的领域中上也是恰当的,发布后再发行的唯一方式是通过采矿。不同于这些示例,采矿同时也是通过在块链中创建,验证,发布和传播块来保护网络的方法。 4 | 采矿以太网=保护网络=验证计算 5 | 6 | ## 那么什么是采矿呢? 7 | 8 | 像所有块链技术一样,Ethereme Frontier使用激励驱动的安全模型。大家一致的看法就是选择具有最高难度的块。矿工生产块,其他人检查有效性。除了其他良好形式的标准之外,块仅在包含给定难度的 **工作证明(PoW)** 时才有效。请注意,在Ethereum 1.1中,这可能会被一个 **证据模型** 所取代。 9 | 10 | 工作算法中使用的证明被称为[Ethash](https://github.com/ethereum/wiki/wiki/Ethash)([Dagger-Hashimoto](https://github.com/ethereum/wiki/wiki/Dagger-Hashimoto)的修改版本涉及寻找随机数输入到算法,使得结果低于一个特定的取决于难度的阈值。也就是是说,在Pow算法中,当验证工作十分琐碎和简单,不存在比枚举更好的策略。 11 | 如果输出具有均匀的分布,那么我们可以保证平均找到一个随机数所需的时间取决于难度阈值,故可以通过操纵难度来控制找到新块的时间。 12 | 13 | 动态调整难度,平均每12秒(即12秒的block时间)由整个网络产生一个块。这种时间间隔基本上是维护系统状态的同步,并保证维护一个分叉(允许双重支出)或重写历史是不可能的,除非攻击者拥有超过一半的网络挖掘能力(所谓的51%攻击)。 14 | 15 | 参与网络的任何节点都可以是矿工,并且其采矿的预期收入将与其相对的挖掘功率或哈希率成正比,即通过网络的总哈希率进行归一化的每秒尝试的时间数。 16 | 17 | Ethash PoW记忆力很强,使得它基本上具有ASIC抗性。这基本上意味着计算PoW需要选择依赖于随机数和块头的固定资源的子集。这个资源(几GB大小的数据)被称为[DAG](https://github.com/ethereum/wiki/wiki/Ethash-DAG)。所述的DAG在每30000块中完全不同的(100小时的窗口,称为epoch),并需要一段时间来产生。由于DAG只依赖于块高度,所以它可以被预先生成,但是如果不是,则客户端需要等待该过程的结束来生成块。除非客户端预先提前拖延时间,网络可能会在每个epoch转换时遇到巨大的块延迟。 18 | 19 | 作为一种特殊情况,当您从头开始创建节点时,只有当DAG为当前epoch构建时,挖掘才会启动。 20 | 21 | ## 挖矿奖励 22 | 23 | 请注意,挖取“真正的”ether将以Frontier版本开始。在Olympics testnet中,在Frontier pre-release上挖取的ether没有任何价值(参见[Olympic rewards](https://blog.ethereum.org/2015/05/09/olympic-frontier-pre-release/))。 24 | 25 | 成功挖出块的PoW矿工会收到: 26 | * 挖出块后的 **静态奖励块**,正好有5.0个Ether 27 | * 所有在块内消耗的gas,即在获胜矿工提交的块中执行所有交易所消耗的所有gas,均由发件人补偿。作为协商一致协议的一部分,所发生的gas消耗被记入矿工的帐户。随着时间的推移,预计这些将使获得静态块奖励变得更加困难。 28 | * 作为块的一部分的额外奖励也包括叔叔块(Uncles),每个叔叔占额外块的1/32 29 | 30 | 叔叔是旧有的块,也就是说父系块是包含块的祖先(最多6个块)。奖励有效的叔叔块(Uncles),以消除网络滞后对采矿奖励分散的影响,从而增加安全性。PoW矿工成功挖出的块中所包含的叔叔块(Uncles)将接收静态块7/8 = 4.375 ether作为奖励。每个块最多允许2个叔叔。 31 | 32 | ## Ethash DAG 33 | 34 | Ethash使用DAG(有向非循环图)作为工作验证算法,DAG是为每个epoch生成的,即每30000个块(100小时)就生成一个。DAG需要很长时间才能生成。如果clients只在需要时生成,那么在发现新纪元(epoch)的第一个块之前,您会经历在每个epoch过渡期间的漫长等待。然而,DAG只取决于块号,所以它可以提前计算,以避免在每个epoch过渡期间的长时间等待。geth实现DAG自动生成,并一次维护两个DAGS,以实现平滑的历元(epoch)转换。当从控制台控制采矿时,DAG自动生成被打开和关闭。如果使用`--mine`选项启动ether,DAG自动生成被默认打开。请注意,客户端共享DAG资源,如果你在运行任何客户端的多个实例,请确保DAG自动生成至少在一个客户端上被打开 35 | 36 | 为任意时期生成DAG: 37 | 38 | geth makedag 39 | 40 | 例如`geth makedag 360000 ~/.ethash`。请注意,ethash使用`~/.ethash`(Mac/Linux)或`~/AppData/Ethash`(Windows)作为DAG,以便它可以在客户端之间共享。 -------------------------------------------------------------------------------- /3.2在geth上用CPU采矿.md: -------------------------------------------------------------------------------- 1 | ## 在Geth上用CPU采矿 2 | 3 | 在Ethereum的第一个发行版Frontier上,你只需要一个CPU和一个Ethereum客户端geth,你只需要一个GPU和b)一个Ethereum客户端,Geth。就可以用CPU采矿,但是效率太低,无法保持任何价值。 4 | 目前,Geth只包括一名CPU矿工,团队正在测试[GPU miner branch](https://github.com/ethereum/go-ethereum/tree/gpu_miner),但这不会是Frontier的一部分。 5 | 6 | Ethereum的C++版本实现还提供了一个GPU矿工,它们都是Eth(其CLI),AlethZero(其GUI)和EthMiner(独立矿工)的一部分。 7 | 8 | **注意**:在采矿之前,确保你的blockchain完全和主链同步 9 | 否则您无法在主链上进行采矿。 10 | 当您用geth启动您的ethereum节点时,默认情况下不会采矿。要在采矿模式下启动,您可以使用`--mine` []命令行选项](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)。`-minerthreads`参数可用于设置并行采矿的线程数(默认为处理器核心总数) 11 | 12 | geth --mine --minerthreads=4 13 | 14 | 您还可以使用[控制台](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console#adminminerstart)在运行时启动和停止CPU挖掘。`miner.start`采用可选参数控制采矿者的线程数量。 15 | 16 | > miner.start(8) 17 | true 18 | > miner.stop() 19 | true 20 | 21 | 请注意,如果您与网络同步(因为您在我们的共识块之上挖矿),那么挖掘真正的ether才是有意义的。因此,eth blockchain下载器/同步器将延迟采矿直到同步完成,然后在采矿自动启动,除非您用`miner.stop()`取消。 22 | 23 | 为了获得ether,您必须具有您的 **etherbase**(或 **coinbase**)地址集。此etherbase默认为您的[主帐户](https://github.com/ethereum/go-ethereum/wiki/Managing-your-accounts)。如果您没有etherbase地址,则`geth --mine`不会启动。 24 | 25 | 您可以在命令行中设置etherbase: 26 | 27 | geth --etherbase 1 --mine 2>> geth.log // 1 is index: second account by creation order OR 28 | geth --etherbase '0xa4d8e9cae4d04b093aac82e6cd355b6b963fb7ff' --mine 2>> geth.log 29 | 30 | 您也可以在控制台上重置etherbase: 31 | 32 | miner.setEtherbase(eth.accounts[2]) 33 | 34 | 请注意,您的etherbase不需要是本地帐户的地址,只是现有帐户的地址。 35 | 36 | 有一个选项可以[添加额外的数据](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console#adminminersetextra)(仅32字节)到您的开采块上。按惯例,这被解释为一个unicode字符串,所以你可以设置你的简短的vanity tag 37 | 38 | miner.setExtra("ΞTHΞЯSPHΞЯΞ") 39 | ... 40 | debug.printBlock(131805) 41 | BLOCK(be465b020fdbedc4063756f0912b5a89bbb4735bd1d1df84363e05ade0195cb1): Size: 531.00 B TD: 643485290485 { 42 | NoNonce: ee48752c3a0bfe3d85339451a5f3f411c21c8170353e450985e1faab0a9ac4cc 43 | Header: 44 | [ 45 | ... 46 | Coinbase: a4d8e9cae4d04b093aac82e6cd355b6b963fb7ff 47 | Number: 131805 48 | Extra: ΞTHΞЯSPHΞЯΞ 49 | ... 50 | } 51 | 52 | 可以参考这个[提案](https://github.com/ethereum/wiki/wiki/Extra-Data) 53 | 54 | After you successfully mined some blocks, you can check the ether balance of your etherbase account. Now assuming your etherbase is a local account: 55 | > eth.getBalance(eth.coinbase).toNumber(); 56 | '34698870000000' 57 | 58 | 您可以使用[`miner.hashrate`](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console#adminminerhashrate)检查您的哈希率,结果为H/s(每秒哈希操作) 59 | 60 | > miner.hashrate 61 | 712000 62 | 63 | 成功开采了一些块后,可以查看您etherbase帐户的余额。现在假设你的etherbase是一个本地帐户: 64 | 65 | > eth.getBalance(eth.coinbase).toNumber(); 66 | '34698870000000' 67 | 68 | 69 | 为了将您的收入用于交易的[花费gas](https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions),您需要将此帐户解锁 70 | 71 | > personal.unlockAccount(eth.coinbase) 72 | Password 73 | true 74 | 75 | 您可以通过以下代码片段在控制台上检查特定矿工(地址)挖掘哪些块: 76 | 77 | function minedBlocks(lastn, addr) { 78 | addrs = []; 79 | if (!addr) { 80 | addr = eth.coinbase 81 | } 82 | limit = eth.blockNumber - lastn 83 | for (i = eth.blockNumber; i >= limit; i--) { 84 | if (eth.getBlock(i).miner == addr) { 85 | addrs.push(i) 86 | } 87 | } 88 | return addrs 89 | } 90 | // scans the last 1000 blocks and returns the blocknumbers of blocks mined by your coinbase 91 | // (more precisely blocks the mining reward for which is sent to your coinbase). 92 | minedBlocks(1000, eth.coinbase); 93 | //[352708, 352655, 352559] 94 | 95 | 请注意,经常会发现一个块,但它从未成为规范链。这意味着当您的本地链包括您的开采块时,当前状态将显示您的帐户的挖矿奖励。但是,一段时间后,更好的链被发现,我们切换到一个不包括您的块的链中,因此没有矿工奖励被记入。当一名矿工监测他们的coinbase余额时,很有可能会发现它可能波动很大。 96 | 97 | log日志显示5块后被确认的当地采矿块。目前,您可能会发现从这些日志中生成开采块的列表更为方便快捷。 98 | 99 | 采矿成功取决于设定块的难度。块难度动态调整每个块,以调节网络散列能力,产生12秒的阻塞时间。因此,您找到一个块的可能性与您相对于难度的哈希率有关。你发现一个块需要等待的预计时间可以用以下代码来估计: 100 | 101 | 粗略估计: 102 | 103 | etm = eth.getBlock("latest").difficulty/miner.hashrate; // estimated time in seconds 104 | Math.floor(etm / 3600.) + "h " + Math.floor((etm % 3600)/60) + "m " + Math.floor(etm % 60) + "s"; 105 | // 1h 3m 30s 106 | -------------------------------------------------------------------------------- /3.3GPU挖矿.md: -------------------------------------------------------------------------------- 1 | # GPU挖矿 2 | ## 硬件 3 | 4 | 该算法是内存困难的,为了将DAG安装到内存中,每个GPU需要1-2GB的RAM。如果你遇到`Error GPU mining. GPU memory fragmentation?`,那就意味着你内存不足 5 | GPU挖矿也在OpenCL中实现,因此AMD GPU将比同类NVIDIA GPU“更快”。ASIC和FPGA相对效率低下,因此不鼓励。 6 | 要获得openCL的芯片组和平台,请尝试: 7 | * [AMD SDK openCL](http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing-app-sdk/) 8 | 9 | * [NVIDIA CUDA openCL](https://developer.nvidia.com/cuda-downloads) 10 | 11 | ## 在Ubuntu上 12 | ### 硬件 13 | 14 | * http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing 15 | * http://developer.amd.com/tools-and-sdks/graphics-development/display-library-adl-sdk/ 16 | 17 | 下载`ADL_SDK8.zip`和` AMD-APP-SDK-v2.9-1.599.381-GA-linux64.sh` 18 | 19 | ./AMD-APP-SDK-v2.9-1.599.381-GA-linux64.sh 20 | ln -s /opt/AMDAPPSDK-2.9-1 /opt/AMDAPP 21 | ln -s /opt/AMDAPP/include/CL /usr/include 22 | ln -s /opt/AMDAPP/lib/x86_64/* /usr/lib/ 23 | ldconfig 24 | reboot 25 | 26 | apt-get install fglrx-updates 27 | // wget, tar, opencl 28 | sudo aticonfig --adapter=all --initial 29 | sudo aticonfig --list-adapters 30 | * 0. 01:00.0 AMD Radeon R9 200 Series 31 | 32 | * - Default adapter 33 | 34 | ### Nvidia 35 | 36 | 以下说明适应大部分使用Ubuntu 14.04和Nvidia GPU的任何系统。 [设置一个EC2实例进行挖掘](https://forum.ethereum.org/discussion/comment/8889/#Comment_8889) 37 | 38 | ## 在MacOS X上 39 | 40 | wget http://developer.download.nvidia.com/compute/cuda/7_0/Prod/local_installers/cuda_7.0.29_mac.pkg 41 | sudo installer -pkg ~/Desktop/cuda_7.0.29_mac.pkg -target / 42 | brew update 43 | brew tap ethereum/ethereum 44 | brew reinstall cpp-ethereum --with-gpu-mining --devel --headless --build-from-source 45 | 46 | 你可以检查你的冷却状态: 47 | 48 | aticonfig --adapter=0 --od-gettemperature 49 | 50 | ## 挖矿软件 51 | 52 | geth的官方Frontier版本只支持CPU矿工。我们正在开发一个[GPU矿工](https://github.com/ethereum/go-ethereum/tree/gpuminer),但它可能不适用于Frontier版本。不过,Geth可以与ethminer结合使用,使用独立的矿工作为工作人员,geth作为调度程序,他们通过[JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC)进行通信。 53 | 54 | Ethereum(未正式发布)的[C++实现](https://github.com/ethereum/cpp-ethereum/)具有GPU矿工。它可以被eth,AlethZero(GUI)和ethMiner(独立矿工)所使用。 55 | 56 | 您可以通过`ppa`在linux上[安装](https://github.com/ethereum/cpp-ethereum/wiki),通过brew tap在MacOS上安装,或直接从源代码编译安装。 57 | 58 | 在MacOS上: 59 | 60 | brew install cpp-ethereum --with-gpu-mining --devel --build-from-source 61 | 62 | 在Linux上: 63 | 64 | apt-get install cpp-ethereum 65 | 66 | 在Windows上: https://github.com/ethereum/cpp-ethereum/wiki/Building-on-Windows 67 | 68 | ## 结合ethminer的GPU挖矿 69 | 70 | 用eth挖矿: 71 | 72 | eth -m on -G -a -i -v 8 // 73 | 74 | 从源文件安装ethminer: 75 | 76 | cd cpp-ethereum 77 | cmake -DETHASHCL=1 -DGUI=0 78 | make -j4 79 | make install 80 | 81 | 要设置GPU挖矿,您需要一个coinbase帐户。它可以是本地或远程创建的帐户。 82 | 83 | ### 使用ethminer与geth 84 | 85 | geth account new 86 | geth --rpc --rpccorsdomain localhost 2>> geth.log & 87 | ethminer -G // -G for GPU, -M for benchmark 88 | tail -f geth.log 89 | 90 | `ethminer`在端口8545(geth中的默认RPC端口)上与geth进行通信。您可以通过geth上的[`--rpcport`](https://github.com/ethereum/go-ethereum/Command-Line-Options)选项来更改。Ethminer会找到任何端口。请注意,您需要使用`--rpccorsdomain localhost`设置CORS头。您还可以在`ethminer`上使用 91 | `-F http://127.0.0.1:3301`设置端口。如果您希望在同一台计算机上实现几个实例挖掘,那么设置端口是必要的,尽管这有点无意义。如果您在私有群集上进行测试,建议您改用CPU。 92 | 93 | 另外请注意,你无需给`geth`设置`--mine`选项,或者在控制台开启旷工,除非你想在GPU挖矿的同时也进行CPU挖矿 94 | 除非你想要做的GPU挖掘的TOP CPU挖掘开始矿工在控制台中。 95 | 如果默认的`ethminer`不工作,尝试用`--opencl-device X`指定OpenCL设备,其中X为0,1,2等。使用ethminer-M(基准)运行时,您应该看到如下信息: 96 | 97 | Benchmarking on platform: { "platform": "NVIDIA CUDA", "device": "GeForce GTX 750 Ti", "version": "OpenCL 1.1 CUDA" } 98 | 99 | Benchmarking on platform: { "platform": "Apple", "device": "Intel(R) Xeon(R) CPU E5-1620 v2 @ 3.70GHz", "version": "OpenCL 1.2 " } 100 | 101 | 调试 geth: 102 | 103 | geth --rpccorsdomain "localhost" --verbosity 6 2>> geth.log 104 | 105 | 调试 miner: 106 | 107 | make -DCMAKE_BUILD_TYPE=Debug -DETHASHCL=1 -DGUI=0 108 | gdb --args ethminer -G -M 109 | 110 | 111 | 注意:当GPU正在挖矿时,geth的哈希率信息无法获取。查询ethminer的哈希率时,`miner.hashrate`总是返回0 112 | 113 | ## ethminer和eth 114 | 115 | `ethminer`可以通过rpc和`eth`结合使用: 116 | 117 | eth -i -v 8 -j // -j for rpc 118 | ethminer -G -M // -G for GPU, -M for benchmark 119 | tail -f geth.log 120 | 121 | 或者你可以使用eth自己执行GPU挖矿: 122 | 123 | eth -m on -G -a -i -v 8 // -------------------------------------------------------------------------------- /4.1命令行接口和选项.md: -------------------------------------------------------------------------------- 1 | ## 命令行选项 2 | 3 | ``` 4 | geth [global options] command [command options] [arguments...] 5 | 6 | VERSION: 7 | 1.0.0 8 | 9 | COMMANDS: 10 | recover 通过设置新的数量或者哈希块来恢复受损的数据库,见help recover 11 | blocktest 加载一个块测试文件 12 | import 导入一个blockchain文件 13 | export 导出blockchain至文件 14 | upgradedb 升级链中块的数据库 15 | removedb 移除blockchain和状态数据库 16 | dump 从存储中转存特定的块 17 | monitor Geth Monitor: 节点指标监控和可视化 18 | makedag 生成ethash dag(测试用) 19 | version 打印ethereum 版本值 20 | wallet ethereum 预售钱包 21 | account 管理账户 22 | console Geth Console: 交互式JavaScript环境 23 | attach Geth Console: 交互式JavaScript环境 (连接节点) 24 | js 在Geth JavaScript VM中执行给定的JavaScript文件 25 | help 命令列表或者一个命令的帮助项 26 | 27 | GLOBAL OPTIONS: 28 | --identity 自定义节点名称 29 | --unlock 解锁给定账户直到程序退出(需要密码),‘--unlock n’解锁第n个账户,或者创建 30 | --password 使用选项和子命令所需要的密码的密码文件路径 31 | --genesis 插入或者重写创世块 (json 格式) 32 | --bootnodes 空格分隔的enode url,用于p2p发现引导 33 | --datadir "/Users/tron/Library/Ethereum" 使用的数据文件夹 34 | --blockchainversion "3" Blockchain 版本(integer) 35 | --jspath "." 控制台和js子命令使用的JS库路径 36 | --port "30303" 网络监听端口 37 | --maxpeers "25" 网络peer的最大数量 (设置为0,网络不可用) 38 | --maxpendpeers "0" 等待连接尝试的最大数量 (设置为0,默认使用) 39 | --etherbase "0" 挖矿回报的公共地址. 默认使用第一个被创建的地址 40 | --gasprice "1000000000000" 设置采矿交易的最小的gasprice 41 | --minerthreads "8" 挖矿线程数 42 | --mine 开启挖矿 43 | --autodag 开启自动DAG预生成 44 | --nat "any" NAT端口映射机制 (any|none|upnp|pmp|extip:) 45 | --natspec 开启NatSpec确认通知 46 | --nodiscover 关闭peer发现机制 (手动添加除外) 47 | --nodekey P2P节点密钥文件 48 | --nodekeyhex 十六进制的P2P节点秘钥(测试) 49 | --rpc 开启JSON-RPC服务器 50 | --rpcaddr "127.0.0.1" 监听json-rpc服务器的地址 51 | --rpcport "8545" JSON-RPC服务器监听的地址 52 | --rpcapi "db,eth,net,web3" 指定HTTP RPC接口提供的API 53 | --ipcdisable 关闭IPC-RPC服务器 54 | --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" 指定RPC接口提供的API 55 | --ipcpath "/Users/tron/Library/Ethereum/geth.ipc" IPC socket/pipe的文件名 56 | --exec 执行javascript命令(只有结合 console/attach) 57 | --shh 开启 whisper 58 | --vmdebug Virtual Machine debug 输出 59 | --networkid "1" Network Id (integer) 60 | --rpccorsdomain 发送Access-Control-Allow-Origin header上的Domain 61 | --verbosity "3" 日志类型: 0-6 (0=silent, 1=error, 2=warn, 3=info, 4=core, 5=debug, 6=debug detail) 62 | --backtrace_at ":0" 如果设置为持有一个日志语句的文件和行号(如。“block.go:271”),将记录一个堆栈跟踪 63 | --logtostderr 日志写入标准错误而不是文件。 64 | --vmodule "" The syntax of the argument is a comma-separated list of pattern=N, where pattern is a literal file name (minus the ".go" suffix) or "glob" pattern and N is a log verbosity level. 65 | --logfile 输出log至文件 66 | --logjson 发送json结构日志输出到一个文件或为标准输出“-” (默认无json输出) 67 | --pprof 启用本地主机上配置服务器 68 | --pprofport "6060" profiler应该监听的端口 69 | --metrics 开启指标收集和汇报 70 | --solc "solc" 使用的solidity编辑器 71 | --gpomin "1000000000000" 建议的最小gas price 72 | --gpomax "100000000000000" 建议的最大gas price 73 | --gpofull "80" gas price计算的完整块阈值(%) 74 | --gpobasedown "10" 建议的gas price基础下调比率(1/1000) 75 | --gpobaseup "100" 建议的gas price基础上调比率(1/1000) 76 | --gpobasecf "110" 建议的gas price基础校正因子(%) 77 | --help, -h 显示帮助 78 | ``` 79 | 80 | 请注意,datadir的默认值是特定于平台的。有关详细信息,请参阅[备份和还原](https://github.com/ethereum/go-ethereum/wiki/Backup-&-restore)。 81 | 82 | ## 例子 83 | ### 账户 84 | 参见[账户管理](https://github.com/ethereum/go-ethereum/wiki/Managing-your-accounts) 85 | 86 | 把ether的预售钱包导入你的节点(需要密码) 87 | 88 | `geth wallet import /path/to/my/etherwallet.json` 89 | 90 | 把一个EC私钥导入到一个ethereum账户(需要密码) 91 | 92 | `geth account import /path/to/key.prv` 93 | 94 | 95 | ### Geth的JavaScript运行环境 96 | 参见[Geth JavaScript 控制台](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console) 97 | 98 | 打开geth javascript控制台: 99 | 100 | `geth --verbosity 5 --jspath /mydapp/js console 2>> /path/to/logfile` 101 | 102 | 执行使用js API的`test.js`脚本,并把Debug-level记录至`/path/to/logfile` 103 | 104 | `geth --verbosity 6 js test.js 2>> /path/to/logfile` 105 | 106 | ### 导入/导出链并转存块 107 | 从文件中导入blockchain 108 | 109 | `geth import blockchain.bin` 110 | 111 | ### 升级blockchain数据库 112 | 当认证算法改变时,blockchain中的块也必须使用新算法重新导入,Geth会通知用户并提供说明,在需要的时候,何时以及如何处理这个信息 113 | 114 | `geth upgradedb` 115 | 116 | ### 挖矿和网络 117 | 启动两个分别监听30303和30304端口,并且使用不同数据文件目录的挖矿节点: 118 | 119 | `geth --mine --minerthreads 4 --datadir /usr/local/share/ethereum/30303 --port 30303` 120 | `geth --mine --minerthreads 4 --datadir /usr/local/share/ethereum/30304 --port 30304` 121 | 122 | 123 | 开启一个在8000端口上的rpc客户端 124 | 125 | `geth --rpc=true --rpcport 8000 --rpccorsdomain '"*"'` 126 | 127 | 开启无网络的客户端: 128 | 129 | `geth --maxpeers 0 --nodiscover --networdid 3301 js justwannarunthis.js` 130 | 131 | 132 | #### 重新设置Blockchain 133 | 在数据文件目录中,删除Blockchain目录,例如: 134 | `rm -rf /usr/local/share/ethereum/30303/blockchain` 135 | 136 | ### 测试网络中同样的用法 137 | 下面的代码仅在非交互式脚本使用的测试网络和安全环境中有效 138 | ``` 139 | geth --datadir /tmp/eth/42 --password <(echo -n notsosecret) account new 2>> /tmp/eth/42.log 140 | geth --datadir /tmp/eth/42 --port 30342 js <(echo 'console.log(admin.nodeInfo().NodeUrl)') > enode 2>> /tmp/eth/42.log 141 | geth --datadir /tmp/eth/42 --port 30342 --password <(echo -n notsosecret) --unlock primary --minerthreads 4 --mine 2>> /tmp/eth/42.log 142 | ``` 143 | ### Attach 144 | 将控制台附加到一个正在运行的geth实例上,默认情况下,这通过IPC在默认IPC端点上发生,但必要时可以指定自定义端点: 145 | 146 | ``` 147 | geth attach ipc:/some/path 148 | geth attach rpc:http://host:8545 149 | ``` 150 | ### 设置标记的可选方法 151 | **警告** :这不是适应于最新的Frontier 152 | 153 | 可以通过配置文件(默认情况下`/conf.ini`)以及环境变量来设置相同的标志。 154 | 155 | 优先级:default < config file < environment variables < command line 156 | -------------------------------------------------------------------------------- /4.2JSON RPC API.md: -------------------------------------------------------------------------------- 1 | ## JSON RPC API 2 | 3 | 4 | [JSON](http://json.org/) 是轻量级的数据交换格式。它可以表示数字,字符串,有序序列的值,以及名称/值对的集合。 5 | 6 | [JSON-RPC](http://www.jsonrpc.org/specification)是无状态,轻量级的远程过程调用(RPC)协议。这个规范首先定义了几个数据结构及其处理规则。这是传输不可知的,因为这些概念可以在相同的过程中,通过套接字,通过HTTP或许多不同的消息传递环境中使用。它使用JSON([RFC 4627](http://www.ietf.org/rfc/rfc4627.txt))作为数据格式。 7 | 8 | ### JavaScript API 9 | 要让一个内置的JavaScript应用程序与一个ethereum节点进行通信,使用[web3.js](https://github.com/ethereum/web3.js)库,它为RPC方法提供了一个方便的接口。有关更多信息,请参阅[JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API)。 10 | 11 | ## JSON-RPC端点 12 | 默认JSON-RPC端点: 13 | ``` 14 | C++: http://localhost:8545 15 | Go: http://localhost:8545 16 | Py: http://localhost:4000 17 | ``` 18 | 19 | ### Go 20 | 您可以使用该`--rpc`标志启动HTTP JSON-RPC 21 | 22 | `geth --rpc` 23 | 24 | 更改默认端口(8545)和列表地址(localhost): 25 | 26 | `geth --rpc --rpcaddr --rpcport ` 27 | 28 | 如果从浏览器访问RPC,CORS将需要启用适当的域集。否则,JavaScript调用受同源策略的限制,请求将失败: 29 | 30 | `geth --rpc --rpccorsdomain "http://localhost:3000"` 31 | 32 | 也可以使用该命令从[geth控制台](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console)启动JSON RPC `admin.startRPC(addr, port)`。 33 | 34 | ### C++ 35 | 您可以通过带`-j`选项的eth应用程序来启动HTTP JSON-RPC: 36 | 37 | `./eth -j` 38 | 39 | 您还可以指定JSON-RPC端口(默认为8545): 40 | 41 | `./eth -j --json-rpc-port 8079` 42 | 43 | ### Python 44 | 在python中,JSONRPC服务器默认启动并侦听 `127.0.0.1:4000` 45 | 您可以通过提供配置选项来更改端口和监听地址。 46 | 47 | `pyethapp -c jsonrpc.listen_port=4002 -c jsonrpc.listen_host=127.0.0.2 run` 48 | 49 | ## JSON-RPC支持 50 | 51 | | |cpp-ethereum |go-ethereum |py-ethereum| 52 | | ------------- |:-------------:|: -----:| :-----:| 53 | |JSON-RPC 1.0| ✓ | | | 54 | |JSON-RPC 2.0| ✓ | ✓ | ✓ | 55 | |批量请求 | ✓ | ✓ | ✓ | 56 | |HTTP | ✓ |✓ | ✓ | 57 | 58 | ## Output HEX value 输出十六进制的值 59 | 60 | 目前有两个重要的数据类型是通过JSON传递的:未格式化的字节数组和数量。两者都使用十六进制编码传递,但对格式化有不同的要求: 61 | 当编码 **QUANTITIES**(整数,数字)时:编码为十六进制,前缀为“0x”,最紧凑的表示(例外:零表示为“0x0”)。例子: 62 | * 0x41(十进制65) 63 | * 0x400(十进制1024) 64 | * 错误:0x(应始终至少有一个数字 - 零是“0x0”) 65 | * 错误:0x0400(不允许前导零) 66 | * WRONG:ff(前缀必须为0x) 67 | 68 | 当编码 **UNFORMATTED DATA**(字节数组,帐户地址,散列,字节码)时:编码为十六进制,前缀为“0x”,每字节两个十六进制数。例子: 69 | 70 | * 0x41(1个字节,“A”) 71 | * 0x004200(3个字节,“\0B\0”) 72 | * 0x(0个字节,“”) 73 | * 错误:0xf0f0f(必须是偶数个位数) 74 | * 错误:004200(前缀必须是0x) 75 | 76 | 目前,[cpp-ethereum](https://github.com/ethereum/cpp-ethereum) 和 [go-ethereum](https://github.com/ethereum/go-ethereum) 仅通过http提供JSON-RPC通信。 77 | 78 | ## 默认块参数 79 | 以下方法有一个额外的默认块参数: 80 | * eth_getBalance 81 | * eth_getCode 82 | * eth_getTransactionCount 83 | * eth_getStorageAt 84 | * eth_call 85 | 86 | 当请求作用于ethereum的状态时,最后一个默认块参数确定块的高度。 87 | 默认Block参数可以使用以下选项: 88 | * HEX String - 整数块号 89 | * String "earliest" 最开始的创世块 90 | * String "latest" - 最新的开采块 91 | * String "pending" - 待处理状态/交易 92 | 93 | ## JSON RPC API参考 94 | 未翻译,具体参见:https://ethereum.gitbooks.io/frontier-guide/content/rpc.html 95 | -------------------------------------------------------------------------------- /4.3JavaScript API for Dapps.md: -------------------------------------------------------------------------------- 1 | ## Web3 JavaScript Ðapp API 2 | 3 | 要使您的Ðapp在Ethereum上工作,您可以使用[web3.js](https://github.com/ethereum/web3.js)库提供的`web3`对象。在底层,通过[RPC调用](https://github.com/ethereum/wiki/wiki/JSON-RPC)与本地节点进行通信。web3.js与任何暴露出RPC层的Ethereum节点一起使用。 4 | 5 | web3包含`eth`对象 - `web3.eth`(特别用于Ethereum块链互动)和`shh`对象 - `web3.shh`(用于Whisper交互)。随着时间的推移,我们将为每个其他web3协议引入其他对象。这里可以找到[工作实例](https://github.com/ethereum/web3.js/tree/master/example)。 6 | 7 | 如果您想使用web3.js查看一些更复杂的示例,请查看这些有用的[Ðapp模式](https://github.com/ethereum/wiki/wiki/Useful-%C3%90app-Patterns)。 8 | ## 使用回调 9 | 10 | 由于此API旨在与本地RPC节点配合工作,并且其所有功能默认使用同步HTTP request.con 11 | 如果要进行异步请求,可以将可选的回调作为最后一个参数传递给大多数函数。所有回调都使用错误第一的回调样式: 12 | ``` 13 | web3.eth.getBlock(48, function(error, result){ 14 | if(!error) 15 | console.log(result) 16 | else 17 | console.error(error); 18 | }) 19 | ``` 20 | 21 | ## 批量请求 22 | 23 | 批量请求将请求排队,并立即处理它们。 24 | ``` 25 | var batch = web3.createBatch(); 26 | batch.add(web3.eth.getBalance.request('0x0000000000000000000000000000000000000000', 'latest', callback)); 27 | batch.add(web3.eth.contract(abi).at(address).balance.request(address, callback2)); 28 | batch.execute(); 29 | ``` 30 | 31 | ## 关于web3.js中大数字的注释 32 | 33 | 查询余额值的时候,你始终会一个BigNumber对象,因为JavaScript无法正确处理大数字。看下面的例子: 34 | ``` 35 | "101010100324325345346456456456456456456" 36 | // "101010100324325345346456456456456456456" 37 | 101010100324325345346456456456456456456 38 | // 1.0101010032432535e+38 39 | ``` 40 | 41 | web3.js取决于[BigNumber库](https://github.com/MikeMcl/bignumber.js/)并自动添加。 42 | 43 | ``` 44 | var balance = new BigNumber('131242344353464564564574574567456'); 45 | // or var balance = web3.eth.getBalance(someAddress); 46 | 47 | balance.plus(21).toString(10); // toString(10) converts it to a number string 48 | // "131242344353464564564574574567477" 49 | ``` 50 | 51 | 下一个例子是行不通的,因为我们有超过20个浮动点,因此建议,以wei为单位获取余额值,只把它呈现给用户的时候才转换为其他单位: 52 | 53 | ``` 54 | var balance = new BigNumber('13124.234435346456466666457455567456'); 55 | 56 | balance.plus(21).toString(10); // toString(10) converts it to a number string, but can only show max 20 floating points 57 | // "13145.23443534645646666646" // you number would be cut after the 20 floating point 58 | ``` 59 | 60 | ## Web3 Javascript Ðapp API参考 61 | 未翻译,可参见:https://ethereum.gitbooks.io/frontier-guide/content/web3.html 62 | -------------------------------------------------------------------------------- /4.4JavaScript Console.md: -------------------------------------------------------------------------------- 1 | ## JavaScript运行环境 2 | 3 | Ethereum实现了可以在交互式(控制台)或非交互式(脚本)模式下使用的JavaScript运行环境(JSRE)。 4 | Ethereum的Javascript控制台支持完整的[web3 JavaScript Dapp API](https://github.com/ethereum/wiki/wiki/JavaScript-API)和[admin API](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console#javascript-console-api)。 5 | 6 | ## 交互使用:JSRE REPL控制台 7 | 8 | 该`ethereum CLI`可执行的`geth`具有JavaScript控制台(读取、计算、打印和循环(REPL)展现了JSRE),可以使用`console`或`attach`子命令启动。`console`子命令启动geth节点,然后打开控制台。`attach`子命令将无法启动geth节点,而是在运行的geth实例上打开控制台。 9 | ``` 10 | $ geth console 11 | $ geth attach 12 | ``` 13 | 14 | 如果geth节点正在运行非默认的ipc端点,或者您想通过rpc接口进行连接,则附加节点将接受端点。 15 | ``` 16 | $ geth attach ipc:/some/custom/path 17 | $ geth attach rpc:http://191.168.1.1:8545 18 | ``` 19 | 请注意,由于安全原因,默认情况下,geth节点不启动rpc服务,并且通过此接口不提供所有功能。当启动geth节点时带`--rpcapi`参数,或者使用[`admin.startRPC`](https://ethereum.gitbooks.io/frontier-guide/content/admin_startRPC)启动,这些默认值可以被覆盖。 20 | 21 | 假如你需要Log信息,执行: 22 | 23 | `$ geth --verbosity 5 console 2>> /tmp/eth.log` 24 | 25 | 或者关闭Log,以免让Log信息占领你的控制台 26 | 27 | `$ geth console 2>> /dev/null` 28 | 29 | 或 30 | 31 | `$ geth --verbosity 0 console` 32 | 33 | 注意:由于数据库只能由一个进程访问,如果您有一个geth实例已经运行,那么你无法再运行`geth console`。 34 | 35 | ## 非交互式使用:JSRE脚本模式 36 | 37 | 还可以在JavaScript解释器上执行脚本文件,`console`和`attach`子命令接受`--exec`参数作为一个javascript的声明。 38 | 39 | `$ geth --exec "eth.blockNumber" attach` 40 | 41 | 这将打印正在运行的geth实例的当前块号。 42 | 43 | 或使用更复杂的形式执行脚本: 44 | ``` 45 | $ geth --exec 'loadScript("/tmp/checkbalances.js")' attach 46 | $ geth --jspath "/tmp" --exec 'loadScript("checkbalances.js")' attach 47 | ``` 48 | [这里](https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions#example-script)是一个示例脚本 49 | 50 | 使用`--jspath `为您的js脚本设置一个libdir。参数`loadScript()`没有绝对路径,是相对此目录的路径。 51 | 您可以通过输入`exit`或简单地使用快捷键`CTRL-C`将控制台完全退出。 52 | 53 | ## 警告 54 | go-ethereum JSRE使用了具有一些限制的Otto JS VM: 55 | 56 | * “`use strict`”会被解析,但什么都不做。 57 | * 正则表达式引擎(re2 / regexp)与ECMA5规范不完全兼容。 58 | 59 | 请注意,Otto的其他已知限制(即缺乏定时器)被考虑到。Ethereum JSRE实现了`setTimeout`和`setInterval`。除此之外,控制台还提供`admin.sleep(seconds)`和“blocktime sleep”方式`admin.sleepBlocks(number)`。由于ethereum.js使用bignumer.js库(MIT Expat License),它会被自动加载的 60 | 61 | ## 计时器 62 | 除了JS的全部功能(根据ECMA5)之外,ethereum JSRE还增加了各种定时器。它实现了`setInterval`,`clearInterval`,`setTimeout`,`clearTimeout`,你可以在浏览器window中使用。它还提供了`admin.sleep(seconds)`,基于块的定时器的实现。`admin.sleepBlocks(n)`表示一直休眠,直到添加的新块的数量等于或大于n,也可看做是“等待n个确认”。 63 | 64 | # 管理API 65 | 除了官方[DApp API](https://github.com/ethereum/wiki/wiki/JSON-RPC)接口之外,go ethereum节点还支持额外的管理API。这些API是使用[JSON-RPC](http://www.jsonrpc.org/specification)提供的,并遵循DApp API中使用的相同约定。go ethereum软件包中含有一个支持所有额外API的控制台客户端。 66 | 67 | ## 怎样做 68 | 可以为go ethereum后台程序指定API设置,这些API由使用`--${interface}api` 命令行参数的接口提供。通过界面提供通过 go ethereum守护程序的命令行参数提供的API集合。这儿的`${interface}`可以是http接口的`rpc`,或是unix上的Unix套接字的`ipc`,Windows上命名管道。 69 | 70 | 例如,`geth --ipcapi "admin,eth,miner" --rpcapi "eth,web3"`会 71 | * 通过IPC接口启用admin,官方DApp和miner API 72 | * 通过RPC接口启用eth和web3 API 73 | 74 | 请注意,通过`rpc`接口提供的API将允许每个接触此接口的人访问此API(例如DApp)。所以请谨慎决定启用哪个API。默认情况下,geth通过`ipc`接口启用所有API,通过`rpc`接口只启用db,eth,net和web3 API。 75 | 76 | 想知道一个接口提供的modules transaction中可以使用哪个API,例如通过`ipc`,`unix`系统上的接口: 77 | 78 | `echo '{"jsonrpc":"2.0","method":"modules","params":[],"id":1}' | nc -U $datadir/geth.ipc` 79 | 80 | 将给出所有启用的模块,包括版本号: 81 | ``` 82 | { 83 | "id":1, 84 | "jsonrpc":"2.0", 85 | "result":{ 86 | "admin":"1.0", 87 | "db":"1.0", 88 | "debug":"1.0", 89 | "eth":"1.0", 90 | "miner":"1.0", 91 | "net":"1.0", 92 | "personal":"1.0", 93 | "shh":"1.0", 94 | "txpool":"1.0", 95 | "web3":"1.0" 96 | } 97 | } 98 | ``` 99 | ## 综合 100 | 101 | 这些额外的API遵循与官方DApp API相同的约定。Web3可以被[扩展](https://github.com/ethereum/web3.js/pull/229)并被用于使用这些附加的API。 102 | 不同的功能分为多个较小的逻辑分组的API集合。示例是针对[JavaScript控制台](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console)的,但是可以很容易地将其转换为rpc请求。 103 | 104 | 2个示例: 105 | * Console: `miner.start()` 106 | * IPC: `echo '{"jsonrpc":"2.0","method":"miner_start","params":[],"id":1}' | nc -U $datadir/geth.ipc` 107 | * RPC: `curl -X POST --data '{"jsonrpc":"2.0","method":"miner_start","params":[],"id":74}' localhost:8545` 108 | 109 | 以线程的数量为参数: 110 | * Console: `miner.start(4)` 111 | * IPC: `echo '{"jsonrpc":"2.0","method":"miner_start","params":[4],"id":1}' | nc -U $datadir/geth.ipc` 112 | * RPC: `curl -X POST --data '{"jsonrpc":"2.0","method":"miner_start","params":[4],"id":74}' localhost:8545` 113 | 114 | 115 | # 管理API参考 116 | 为翻译,参见:https://ethereum.gitbooks.io/frontier-guide/content/jsre.html 117 | -------------------------------------------------------------------------------- /4.接口.md: -------------------------------------------------------------------------------- 1 | ## 接口 2 | 3 | * Javascript控制台:可以使用交互式控制台启动`geth`,它提供了一个JavaScript运行时环境,暴露了一个JavaScript API与您的节点进行交互。[Javascript Console API](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console)包含`web3` javascript Ðapp API以及其他管理API 4 | * JSON-RPC服务器:geth可以使用暴露[JSON-RPC API](https://github.com/ethereum/wiki/wiki/JSON-RPC)的json-rpc服务器启动 5 | * [命令行选项](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)记录了命令行参数以及子命令。 6 | -------------------------------------------------------------------------------- /5.10测试合约及交易.md: -------------------------------------------------------------------------------- 1 | ## 测试合同和交易 2 | 通常,您需要采取低级别策略来测试和调试合约及交易。本节介绍一些可以使用的调试工具和实践。为了在不产生实际影响的情况下测试合约和交易,你最好在一个私人的块上测试它。这可以通过配置备用网络ID(选择唯一的整数)和/或禁用peer来实现。测试时推荐您使用备用数据目录和端口,这使得您甚至不会意外与现场运行的节点冲突(假设使用默认值运行)。使用带有性能分析的VM调试模式开启你的geth,推荐最高的日志记录级别: 3 | ``` 4 | geth --datadir ~/dapps/testing/00/ --port 30310 --rpcport 8110 --networkid 4567890 --nodiscover --maxpeers 0 --vmdebug --verbosity 6 --pprof --pprofport 6110 console 2>> ~/dapp/testint/00/00.log 5 | ``` 6 | Before you can submit any transactions, you need mine some ether on your private chain and for that you need an account. See the sections on Mining and Accounts 7 | 8 | 在您提交任何交易之前,您需要在您的私链上挖取一些ether,因此您需要一个帐户。请参阅[采矿](https://github.com/ethereum/go-ethereum/wiki/Mining)和[账户](https://github.com/ethereum/go-ethereum/wiki/Managing-Your-Accounts)部分。 9 | 10 | ``` 11 | // create account. will prompt for password 12 | personal.newAccount("mypassword"); 13 | // name your primary account, will often use it 14 | primary = eth.accounts[0]; 15 | // check your balance (denominated in ether) 16 | balance = web3.fromWei(eth.getBalance(primary), "ether"); 17 | ``` 18 | ``` 19 | // assume an existing unlocked primary account 20 | primary = eth.accounts[0]; 21 | 22 | // mine 10 blocks to generate ether 23 | 24 | // starting miner 25 | miner.start(8); 26 | // sleep for 10 blocks. 27 | admin.sleepBlocks(10); 28 | // then stop mining (just not to burn heat in vain) 29 | miner.stop() ; 30 | balance = web3.fromWei(eth.getBalance(primary), "ether"); 31 | ``` 32 | 创建事务后,可以强制处理它们,具体如下: 33 | ``` 34 | miner.start(1); 35 | admin.sleepBlocks(1); 36 | miner.stop() ; 37 | ``` 38 | 你可以查看你的待处理交易: 39 | ``` 40 | // shows transaction pool 41 | txpool.status 42 | // number of pending txs 43 | eth.getBlockTransactionCount("pending"); 44 | // print all pending txs 45 | eth.getBlock("pending", true).transactions 46 | ``` 47 | 如果您提交合约创建事务,您可以检查所需的代码是否已经插入到当前块链中: 48 | ``` 49 | txhash = eth.sendTansaction({from:primary, data: code}) 50 | //... mining 51 | contractaddress = eth.getTransactionReceipt(txhash); 52 | eth.getCode(contractaddress) 53 | ``` 54 | -------------------------------------------------------------------------------- /5.11注册服务.md: -------------------------------------------------------------------------------- 1 | ## 注册服务 2 | Frontier带有一些非常基本的基础层服务,也包括了大部分的注册商(registrar)。注册商由3个部分组成。 3 | * GlobalRegistrar将名称(字符串)关联到帐户(地址)。 4 | * HashReg将散列关联到哈希(将任何对象映射到“内容”哈希)。 5 | * UrlHint将内容哈希值关联到提示内容的位置。只有在内容存储不是内容寻址的情况下才需要,否则内容哈希已经是内容地址。如果使用它,则从URL获取的内容应该哈希到内容哈希。为了检查内容的真实性,可以检查是否验证。 6 | 7 | ## 创建和部署GlobalRegistrar,HashReg和UrlHint 8 | 如果注册商的合约在blockchain中不是硬编码的(在撰写本文时不是),则注册商需要在每条链上至少部署一次。 9 | 如果你在主链上,主要全球注册商的地址在最新的客户端上是硬编码的,因此你不需要做任何事情。如果你想改变这个或者你是在一个私人链条上,你需要至少部署这些合同一次: 10 | ``` 11 | primary = eth.accounts[0]; 12 | 13 | globalRegistrarAddr = admin.setGlobalRegistrar("", primary); 14 | hashRegAddr = admin.setHashReg("", primary); 15 | urlHintAddr = admin.setUrlHint("", primary); 16 | ``` 17 | 你需要挖矿或等到txs被确认。在新地址上初始化注册商,并检查其他注册商名称是否使用了正确的地址: 18 | ``` 19 | registrar = GlobalRegistrar.at(globalRegistrarAddr); 20 | primary == registrar.owner("HashReg"); 21 | primary == registrar.owner("UrlHint"); 22 | hashRegAddr == registrar.addr("HashReg"); 23 | urlHintAddr registrar.addr("UrlHint"); 24 | ``` 25 | 以下代码返回正确的编码: 26 | ``` 27 | eth.getCode(registrar.address); 28 | eth.getCode(registrar.addr("HashReg")); 29 | eth.getCode(registrar.addr("UrlHint")); 30 | ``` 31 | 从第二次起,在同一个链路以及其他节点上,您只需使用GlobalRegistrars地址进行初始化,其余的则通过它进行处理。 32 | ``` 33 | primary = eth.accounts[0]; 34 | globalRegistrarAddr = "0x225178b4829bbe7c9f8a6d2e3d9d87b66ed57d4f" 35 | 36 | // set the global registrar address 37 | admin.setGlobalRegistrar(globalRegistrarAddr) 38 | // set HashReg address via globalRegistrar 39 | hashRegAddr = admin.setHashReg() 40 | // set UrlHint address via globalRegistrar 41 | urlHintAddr = admin.setUrlHint() 42 | 43 | // (re)sets the registrar variable to a GlobalRegistrar contract instance 44 | registrar = GlobalRegistrar.at(globalRegistrarAddr); 45 | ``` 46 | 如果这是成功的,如果注册商返回地址,您应该可以使用以下命令进行检查: 47 | ``` 48 | registrar.owner("HashReg"); 49 | registrar.owner("UrlHint"); 50 | registrar.addr("HashReg"); 51 | registrar.addr("UrlHint"); 52 | ``` 53 | 下面代码会返回正确编码: 54 | ``` 55 | eth.getCode(registrar.address); 56 | eth.getCode(registrar.addr("HashReg")); 57 | eth.getCode(registrar.addr("UrlHint")); 58 | ``` 59 | 60 | ### 使用注册商服务 61 | 可以在合约和dapps之间提供有用的接口。 62 | 63 | ### 全球注册商 64 | 要保留名称,请注册一个帐号,您需要以下内容: 65 | ``` 66 | registrar.reserve.sendTransaction(name, {from:primary}) 67 | registrar.setAddress.sendTransaction (name, address, true, {from: primary}) 68 | ``` 69 | 70 | 你需要等待交易被确认(当在私链上,你可以强制执行),你可以查询注册商用来检查: 71 | ``` 72 | registrar.owner(name) 73 | registrar.addr(name) 74 | ``` 75 | ### HashReg和UrlHint 76 | HashReg和UrlHint可以与以下abis一起使用: 77 | ``` 78 | hashRegAbi = '[{"constant":false,"inputs":[],"name":"setowner","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_key","type":"uint256"},{"name":"_content","type":"uint256"}],"name":"register","outputs":[],"type":"function"}]' 79 | urlHintAbi = '[{"constant":false,"inputs":[{"name":"_hash","type":"uint256"},{"name":"idx","type":"uint8"},{"name":"_url","type":"uint256"}],"name":"register","outputs":[],"type":"function"}]' 80 | ``` 81 | 设置合同实例: 82 | ``` 83 | hashReg = eth.contract(hashRegAbi).at(registrar.addr("HashReg"))); 84 | urlHint = eth.contract(UrlHintAbi).at(registrar.addr("UrlHint"))); 85 | ``` 86 | 将内容哈希与密钥哈希相关联: 87 | ``` 88 | hashReg.register.sendTransaction(keyhash, contenthash, {from:primary}) 89 | ``` 90 | 将网址与内容哈希相关联: 91 | ``` 92 | urlHint.register.sendTransaction(contenthash, url, {from:primary}) 93 | ``` 94 | 检查决议: 95 | ``` 96 | contenthash = hashReg._hash(keyhash); 97 | url = urlHint._url(contenthash); 98 | ``` 99 | -------------------------------------------------------------------------------- /5.12示例脚本.md: -------------------------------------------------------------------------------- 1 | ## 示例脚本 2 | 下面的示例脚本演示了本教程中讨论的大多数功能,你可以通过[JSRE](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console)使用`geth js script.js 2>>geth.log`来运行它。假如你想在自己的私链上来运行此示例,请通过下面的代码启动geth: 3 | ``` 4 | geth --maxpeers 0 --networkid 123456 --nodiscover --unlock primary js script.js 2>> geth.log 5 | ``` 6 | 注意`networkid`可以是任意非负整数,0总是表示已经存在网络 7 | ``` 8 | personal.newAccount("") 9 | 10 | primary = eth.accounts[0]; 11 | balance = web3.fromWei(eth.getBalance(primary), "ether"); 12 | personal.unlockAccount(primary, "00"); 13 | // miner.setEtherbase(primary) 14 | 15 | miner.start(8); admin.sleepBlocks(10); miner.stop() ; 16 | 17 | // 0xc6d9d2cd449a754c494264e1809c50e34d64562b 18 | primary = eth.accounts[0]; 19 | balance = web3.fromWei(eth.getBalance(primary), "ether"); 20 | 21 | globalRegistrarTxHash = admin.setGlobalRegistrar("0x0"); 22 | //'0x0' 23 | globalRegistrarTxHash = admin.setGlobalRegistrar("", primary); 24 | //'0xa69690d2b1a1dcda78bc7645732bb6eefcd6b188eaa37abc47a0ab0bd87a02e8' 25 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 26 | //true 27 | globalRegistrarAddr = eth.getTransactionReceipt(globalRegistrarTxHash).contractAddress; 28 | //'0x3d255836f5f8c9976ec861b1065f953b96908b07' 29 | eth.getCode(globalRegistrarAddr); 30 | //... 31 | admin.setGlobalRegistrar(globalRegistrarAddr); 32 | registrar = GlobalRegistrar.at(globalRegistrarAddr); 33 | 34 | hashRegTxHash = admin.setHashReg("0x0"); 35 | hashRegTxHash = admin.setHashReg("", primary); 36 | txpool.status 37 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 38 | hashRegAddr = eth.getTransactionReceipt(hashRegTxHash).contractAddress; 39 | eth.getCode(hashRegAddr); 40 | 41 | registrar.reserve.sendTransaction("HashReg", {from:primary}); 42 | registrar.setAddress.sendTransaction("HashReg",hashRegAddr,true, {from:primary}); 43 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 44 | registrar.owner("HashReg"); 45 | registrar.addr("HashReg"); 46 | 47 | urlHintTxHash = admin.setUrlHint("", primary); 48 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 49 | urlHintAddr = eth.getTransactionReceipt(urlHintTxHash).contractAddress; 50 | eth.getCode(urlHintAddr); 51 | 52 | registrar.reserve.sendTransaction("UrlHint", {from:primary}); 53 | registrar.setAddress.sendTransaction("UrlHint",urlHintAddr,true, {from:primary}); 54 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 55 | registrar.owner("UrlHint"); 56 | registrar.addr("UrlHint"); 57 | 58 | globalRegistrarAddr = "0xfd719187089030b33a1463609b7dfea0e5de25f0" 59 | admin.setGlobalRegistrar(globalRegistrarAddr); 60 | registrar = GlobalRegistrar.at(globalRegistrarAddr); 61 | admin.setHashReg(""); 62 | admin.setUrlHint(""); 63 | 64 | ///// /////////////////////////////// 65 | 66 | admin.stopNatSpec(); 67 | primary = eth.accounts[0]; 68 | personal.unlockAccount(primary, "00") 69 | 70 | globalRegistrarAddr = "0xfd719187089030b33a1463609b7dfea0e5de25f0"; 71 | admin.setGlobalRegistrar(globalRegistrarAddr); 72 | registrar = GlobalRegistrar.at(globalRegistrarAddr); 73 | admin.setHashReg("0x0"); 74 | admin.setHashReg(""); 75 | admin.setUrlHint("0x0"); 76 | admin.setUrlHint(""); 77 | 78 | 79 | registrar.owner("HashReg"); 80 | registrar.owner("UrlHint"); 81 | registrar.addr("HashReg") 82 | registrar.addr("UrlHint"); 83 | 84 | 85 | ///////////////////////////////////// 86 | eth.getBlockTransactionCount("pending"); 87 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 88 | 89 | source = "contract test {\n" + 90 | " /// @notice will multiply `a` by 7.\n" + 91 | " function multiply(uint a) returns(uint d) {\n" + 92 | " return a * 7;\n" + 93 | " }\n" + 94 | "} "; 95 | contract = eth.compile.solidity(source).test; 96 | txhash = eth.sendTransaction({from: primary, data: contract.code}); 97 | 98 | eth.getBlock("pending", true).transactions; 99 | 100 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 101 | contractaddress = eth.getTransactionReceipt(txhash).contractAddress; 102 | eth.getCode(contractaddress); 103 | 104 | multiply7 = eth.contract(contract.info.abiDefinition).at(contractaddress); 105 | fortytwo = multiply7.multiply.call(6); 106 | 107 | ///////////////////////////////// 108 | 109 | // register a name for the contract 110 | registrar.reserve.sendTransaction(primary, {from: primary}); 111 | registrar.setAddress.sendTransaction("multiply7", contractaddress, true, {from: primary}); 112 | //////////////////////// 113 | 114 | admin.stopNatSpec(); 115 | filename = "/info.json"; 116 | contenthash = admin.saveInfo(contract.info, "/tmp" + filename); 117 | admin.register(primary, contractaddress, contenthash); 118 | eth.getBlock("pending", true).transactions; 119 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 120 | 121 | admin.registerUrl(primary, contenthash, "file://" + filename); 122 | eth.getBlock("pending", true).transactions; 123 | miner.start(1); admin.sleepBlocks(1); miner.stop(); 124 | 125 | //////////////////// 126 | 127 | // retrieve contract address using global registrar entry with 'multply7' 128 | contractaddress = registrar.addr("multiply7); 129 | // retrieve the info using the url 130 | info = admin.getContractInfo(contractaddress); 131 | multiply7 = eth.contract(info.abiDefinition).at(contractaddress); 132 | // try Natspec 133 | admin.startNatSpec(); 134 | fortytwo = multiply7.multiply.sendTransaction(6, { from: primary }); 135 | ``` 136 | -------------------------------------------------------------------------------- /5.13.1接待员.md: -------------------------------------------------------------------------------- 1 | ## 你的第一个公民:接待员 2 | 3 | 既然你已经掌握了Ethereum的基础知识,那么我们来谈谈你的第一份严肃的合同。Frontier是一个广阔开放的领域,有时你可能会感到孤独,所以我们的第一个生意是创造一个自动伴侣,当你感到孤独时迎接你。我们称他为“Greeter”。 4 | Greeter是一个存活在blockchain上的智能数字实体,根据其输入,能够与任何与之交互的人进行对话。它或许不健谈,但它是一个很好的听众。这是它的代码: 5 | ``` 6 | contract mortal { 7 | /* Define variable owner of the type address*/ 8 | address owner; 9 | 10 | /* this function is executed at initialization and sets the owner of the contract */ 11 | function mortal() { owner = msg.sender; } 12 | 13 | /* Function to recover the funds on the contract */ 14 | function kill() { if (msg.sender == owner) suicide(owner); } 15 | } 16 | 17 | contract greeter is mortal { 18 | /* define variable greeting of the type string */ 19 | string greeting; 20 | 21 | /* this runs when the contract is executed */ 22 | function greeter(string _greeting) public { 23 | greeting = _greeting; 24 | } 25 | 26 | /* main function */ 27 | function greet() constant returns (string) { 28 | return greeting; 29 | } 30 | } 31 | ``` 32 | 你会注意到,这段代码中有两个不同的合约:“mortal”和“greeter”。这是因为Solidity(我们使用的高级合约语言)具有继承性,这意味着一个合同可以继承另一个合约的特征。这对于简化编码非常有用,因为每次不需要重写合同的常见特征,并且所有合约都可以写成更小,更可读的块。所以只要宣布greeter是mortal,你就继承了“mortal”合约的所有特征,并保持了这个简洁易懂的代码。 33 | 34 | 从“mortal”继承的特征仅仅意味着,在不再需要合约的情况下,greeter合约可以被其所有者杀死,清理blockchain并收回锁定的资金。在默认情况下,ethereum中的合约是永生的,没有所有者,这意味着一旦部署了,作者就不再有特权了。在部署前考虑一下。 35 | 36 | ### 安装编译器 37 | 在您能够部署之前,您将需要准备两件事:编译过的代码和应用程​​序二进制接口(Application Binary Interface),这是一种定义如何与合约进行交互的参考模板。 38 | 前者可以使用编译器获得。您应该在您的`geth`控制台上内置一个solidity编译器。要测试它,请使用以下命令: 39 | ``` 40 | eth.getCompilers() 41 | ``` 42 | 如果你安装它,它应该输出如下: 43 | ``` 44 | ['Solidity' ] 45 | ``` 46 | 如果命令返回错误,那么您需要安装它。 47 | 48 | ### 使用在线编译器 49 | 如果您没有安装solC,我们有一个[在线的solidity编译器](https://chriseth.github.io/browser-solidity/)可供使用。但请注意,如果编译器受到威胁,则您的合同不安全。因此,如果您想使用在线编译器,我们鼓励您[建立自己的在线编辑器](https://github.com/ethereum/browser-solidity)。 50 | 51 | ### 在Ubuntu上安装SolC 52 | 按control+c退出控制台(或键入exit)并返回到命令行。打开终端并执行以下命令: 53 | ``` 54 | sudo add-apt-repository ppa:ethereum/ethereum 55 | sudo apt-get update 56 | sudo apt-get install solc 57 | which solc 58 | ``` 59 | 记下最后一行给出的路径,你很快就会用到。 60 | 61 | ### 在Mac上安装SolC 62 | 63 | 你需要[brew](https://brew.sh/),以在你的mac上安装SolC 64 | ``` 65 | brew install cpp-ethereum 66 | brew linkapps cpp-ethereum 67 | which solc 68 | ``` 69 | ### 在Windows上安装SolC 70 | 你需要借助[chocolatey](http://chocolatey.org/)来安装SolC 71 | ``` 72 | cinst -pre solC-stable 73 | ``` 74 | Windows比这更复杂,你需要等一下。 75 | 76 | 如果您安装了SolC Solidity Compiler,则需要通过删除空格来重新格式化,以使其适合字符串变量(有一些[在线工具](http://www.textfixer.com/tools/remove-line-breaks.php)可以执行此操作) 77 | 78 | ### 从源文件编译 79 | ``` 80 | git clone https://github.com/ethereum/cpp-ethereum.git 81 | mkdir cpp-ethereum/build 82 | cd cpp-ethereum/build 83 | cmake -DJSONRPC=OFF -DMINER=OFF -DETHKEY=OFF -DSERPENT=OFF -DGUI=OFF -DTESTS=OFF -DJSCONSOLE=OFF .. 84 | make -j4 85 | make install 86 | which solc 87 | ``` 88 | ### 将您的编译器链接到Geth 89 | 现在[返回到控制台]并输入此命令来安装solC,将`path / to / solc`替换为您执行的最后一个命令的路径: 90 | ``` 91 | admin.setSolc("path/to/solc") 92 | ``` 93 | 现在再次键入: 94 | ``` 95 | eth.getCompilers() 96 | ``` 97 | 如果您现在已经安装了SolC,那么恭喜,您可以继续阅读。如果没有,那么请去我们的[论坛](http://forum.ethereum.org/)或者[subreddit](https://www.reddit.com/r/ethereum/),促使我们让此过程更容易。 98 | 99 | ## 编译合同 100 | 如果您安装了编译器,则现在需要通过删除换行符来重新格式化合同,以使其符合字符串变量(有一些在线工具可以执行此操作): 101 | ``` 102 | var greeterSource = 'contract mortal { address owner; function mortal() { owner = msg.sender; } function kill() { if (msg.sender == owner) suicide(owner); } } contract greeter is mortal { string greeting; function greeter(string _greeting) public { greeting = _greeting; } function greet() constant returns (string) { return greeting; } }' 103 | 104 | var greeterCompiled = web3.eth.compile.solidity(greeterSource) 105 | ``` 106 | 你现在已经编译了你的代码。现在你需要准备部署,这包括设置一些变量,就像你的问候语。编辑下面的第一行,输入一些比“Hello World!”更有趣的话,并执行以下命令: 107 | ``` 108 | var _greeting = "Hello World!" 109 | var greeterContract = web3.eth.contract(greeterCompiled.greeter.info.abiDefinition); 110 | 111 | var greeter = greeterContract.new(_greeting,{from:web3.eth.accounts[0], data: greeterCompiled.greeter.code, gas: 1000000}, function(e, contract){ 112 | if(!e) { 113 | 114 | if(!contract.address) { 115 | console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..."); 116 | 117 | } else { 118 | console.log("Contract mined! Address: " + contract.address); 119 | console.log(contract); 120 | } 121 | 122 | } 123 | }) 124 | ``` 125 | ### 使用在线编译器 126 | 如果您没有安装solC,可以直接使用在线编译器。将上面的源代码复制到在线solidity编译器,然后你的编译代码应该出现在左窗格中。将标记为Geth deploy框中的代码复制到文本文件。现在把第一行改成你的问候语: 127 | ``` 128 | var _greeting = "Hello World!" 129 | ``` 130 | 现在您可以将生成的文本粘贴到您的geth窗口。等待三十秒钟,您会看到如下消息: 131 | ``` 132 | Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e 133 | ``` 134 | 您可能会被要求提供您在开始时选择的密码,因为您需要支付部署合约所需的gas费用。这份合约估计需要17.2万个gas用来部署(根据在线solidity编译器),在撰写本文时,测试网上的gas价格为1至10 microethers/每单位gas(昵称为“szabo”,换算成wei后是1后面加12个0)。要知道ether的最新价格,您可以在[网络统计页面](https://stats.ethdev.com/)上看到最新的gas价格,并将这两个术语相乘。 135 | 136 | 请注意,成本并不支付给ethereum开发人员,而是付给矿工,他们提供维护网络运行的计算机。gas价格是由当前市场供求计算的。如果gas价格太高,你可以成为矿工,降低你的要价。 137 | 不到一分钟之后,你应该有一个合约地址的日志,这意味着你已经成功地部署了你的合约。您可以使用以下命令验证已部署的代码(已编译): 138 | ``` 139 | eth.getCode(greeter.address) 140 | ``` 141 | 如果它返回除“0x”之外的任何东西,那么恭喜!你的小Greeter是活的!如果合约再次创建(通过执行另一个eth.sendTransaction),它将被发布到一个新的地址。 142 | ### 运行Greeter 143 | 为了调用您的机器人,只需在您的终端中键入以下命令: 144 | ``` 145 | greeter.greet(); 146 | ```` 147 | 由于此调用在blockchain上不改变任何东西,因此立即返回,无需任何gas成本。你应该看到它返回你的问候语: 148 | ``` 149 | 'Hello World!' 150 | ``` 151 | ### 让其他人与您的代码进行交互 152 | 153 | 为了让其他人运行你的合约,他们需要两件东西:合约所在的地址和ABI(应用二进制接口),这是一种用户手册,描述其功能的名称以及如何调用它们。为了获取他们,运行以下命令: 154 | ``` 155 | greeterCompiled.greeter.info.abiDefinition; 156 | greeter.address; 157 | ``` 158 | 然后,您可以实例化一个可以用于在连接到网络的任何计算机上调用合约的JavaScript对象。替换'ABI'和'地址'以在javascript中创建一个合约对象: 159 | ``` 160 | var greeter = eth.contract(ABI).at(Address); 161 | var greeter = eth.contract(ABI).at(Address); 162 | ``` 163 | 任何人都可以通过简单的调用来实例化这个特定的例子: 164 | ``` 165 | var greeter2 = eth.contract([{constant:false,inputs:[],name:'kill',outputs:[],type:'function'},{constant:true,inputs:[],name:'greet',outputs:[{name:'',type:'string'}],type:'function'},{inputs:[{name:'_greeting',type:'string'}],type:'constructor'}]).at('greeterAddress'); 166 | ``` 167 | 将`greeterAddress`替换为您的合同地址。 168 | 169 | ** 提示:如果您的计算机中没有正确安装solidity编译器,则可以从在线编译器获取ABI。为此,请使用下面的代码,仔细地使用编译器中的abi替换greeterCompiled.greeter.info.abiDefinition。** 170 | 171 | ### 自己清理后: 172 | 173 | 你的第一份合约生效时,你肯定很兴奋,但这个兴奋有时会慢慢消失,当所有者继续写下进一步的合约时,导致在blockchain上被放弃的合约很不开心。未来,可能会实施blockchain租金,以增加blockchain的可扩展性,但现在,成为一个好的公民,人性化地放弃了你的遗弃的机器人。 174 | 175 | 与上一次不同,我们不会调用,因为我们希望改变blockchain上的东西。这要求将交易发送到网络,并为所做的更改支付费用。自杀由网络补贴,因此比一般的交易费用要少得多。 176 | ``` 177 | greeter.kill.sendTransaction({from:eth.accounts[0]}) 178 | ``` 179 | 您可以根据看到是否返回0来验证合约是否完成: 180 | ``` 181 | eth.getCode(greeter.contractAddress) 182 | ``` 183 | 请注意,每个合同都必须执行自己的kill条款。在这种特殊情况下,只有创建合同的帐户才能将其杀死。 184 | 185 | 如果你不添加任何杀死条款,它可能永远存在(或者至少直到frontier合约都被擦除),独立于你和任何实际边界,所以在你将其放置网络之前,请检查关于它的本地法律条款,包括对技术出口的任何可能的限制,对言论的限制,也可能是有声数字的民事权利立法。请人性化地对待你的机器人。 186 | -------------------------------------------------------------------------------- /5.13.2注册商.md: -------------------------------------------------------------------------------- 1 | ## 注册你的货币的名称 2 | 所提到的命令只能工作,因为您在本地计算机上实例化了令牌JavaScript对象。如果您向某人发送令牌,则由于他们没有相同的对象而无法将其移动,也不会知道在何处寻找合约或调用其功能。事实上,如果您重新启动控制台,这些对象将被删除,您一直在处理的合约将永远丢失。那么如何在干净的机器上实例化合约? 3 | 有两种方法,通过向您朋友提供您的合同ABI的引用,我们可以快速开始: 4 | ``` 5 | token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at('0x4a4ce7844735c4b6fc66392b200ab6fe007cfca8') 6 | ``` 7 | 只需替换自己的令牌地址的最后一个地址,那么使用此代码段的任何人都可以立即使用您的合同。当然这只适用于这个具体的合同,所以让我们逐步分析一下,看看如何改进这个代码,这样你就可以在任何地方使用它。 8 | 9 | 网络中的所有帐户都被其公共地址引用。但地址长,难以写下来,难以记忆和不变。如果您想要以您的名义生成新帐户,或者升级您的合同代码,则最后一个是特别重要的。为了解决这个问题,有一个默认的名称注册商合同,用于将长地址与简短的,人性化的名称相关联。 10 | 11 | 名称必须仅使用字母数字字符,并且不能包含空格。在未来的版本中,名称注册商可能会实施一个招标过程,以防止名称光占着茅坑,但现在,它是先到先得的原则:只要没有人注册该名称,您可以声明它。 12 | 13 | 首先,如果你注册一个名字,那么你最终不需要硬编码的地址。选择一个不错的硬币名称,并尝试为自己预留。首先,选择你的名字: 14 | ``` 15 | var tokenName = "MyFirstCoin" 16 | ``` 17 | 接着检查下它是否可用 18 | ``` 19 | registrar.addr(tokenName) 20 | ``` 21 | 如果此函数返回“0x00..”,那么你可以宣布此名称属于你了 22 | ``` 23 | registrar.reserve.sendTransaction(tokenName, {from: eth.accounts[0]}); 24 | ``` 25 | 等待先前的交易被确认。等待三十秒钟,然后尝试: 26 | ``` 27 | registrar.owner(myName) 28 | ``` 29 | 如果它返回您的地址,则表示您拥有该名称,并且可以将您选择的名称设置为您想要的任何地址: 30 | ``` 31 | registrar.setAddress.sendTransaction(tokenName, token.address, true,{from: eth.accounts[0]}); 32 | ``` 33 | 如果要将其用作个人昵称,可以替换**eth.accounts[0]** 的** token.address**。 34 | 35 | 等待一会儿,让交易被确认,然后测试下: 36 | ``` 37 | registrar.addr("MyFirstCoin") 38 | ``` 39 | 你可以通过简单地输入名字而不是账户来向任何人或者任何合约发送交易: 40 | ``` 41 | eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("MyFirstCoin"), value: web3.toWei(1, "ether")}) 42 | ``` 43 | ** 提示:请勿将registrar.addr同Registrar.owner搞混了。第一个是该名称指向的地址:任何人都可以将名称指向其他任何地方,就像任何人都可以转发到google.com的链接,但只有该名称的所有者可以更改和更新链接。您可以将两者设置为相同的地址。** 44 | 45 | 现在应该返回您的令牌地址,这意味着以前要实例化的代码现在可以使用名称来替换地址。 46 | ``` 47 | token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at(registrar.addr("MyFirstCoin")) 48 | ``` 49 | 这也意味着货币的所有者可以通过将注册商指向新的合同来更新硬币。这当然要求货币持有人信任Registrar.owner(“MyFirstCoin”)设置的所有者 50 | 51 | 当然,这是一个令人不快的大块代码,只是为了允许他人与合同进行交互。有一些将合同ABI上传到网络的方法正在讨论中,以便所有用户需要的仅仅是合同名称。你可以阅读[这些方法](tps://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions#natspec),但它们是实验性的,将来肯定会发生变化。 52 | -------------------------------------------------------------------------------- /5.13.3货币合约.md: -------------------------------------------------------------------------------- 1 | ## 货币 2 | 什么是货币?货币比他们看起来更有趣和有用,它们本质上只是一个可交易的令牌,但可以变得更多,取决于你如何使用它们。其价值取决于您使用的方式:令牌可用于控制访问(**门票**),可用于组织(**共享**)中的投票权,可以是第三方持有的资产的占位符(**所有权证书**),甚至只能用作社区(**货币**)内的价值交换。+ 3 | 4 | 您可以通过创建一个集中的服务器来完成所有这些工作,但是使用Ethereum令牌合约带有一些免费的功能:一个是一个分散的服务,即使原始服务由任何原因导致宕机,令牌也可以交换。代码可以保证不会创建除原始代码中设置的令牌以外的令牌。最后,通过使每个用户拥有自己的令牌,这消除了一个单一服务器突破可能导致数千客户端资金损失的情况。 5 | 6 | 您可以在不同的blockchain上创建自己的令牌,但是在ethereum上创造更容易。所以您可以将精力集中在创新上,使您的货币脱颖而出。它更安全,因为您的安全由所有正在支持ethereum网络的矿工提供。最后,通过在Ethereum中创建你的令牌,你的硬币将与任何运行在ethereum上其他合约兼容。 7 | 8 | ## 代码 9 | 下面就是我们合约的代码: 10 | ``` 11 | contract token { 12 | mapping (address => uint) public coinBalanceOf; 13 | event CoinTransfer(address sender, address receiver, uint amount); 14 | 15 | /* Initializes contract with initial supply tokens to the creator of the contract */ 16 | function token(uint supply) { 17 | coinBalanceOf[msg.sender] = supply; 18 | } 19 | 20 | /* Very simple trade function */ 21 | function sendCoin(address receiver, uint amount) returns(bool sufficient) { 22 | if (coinBalanceOf[msg.sender] < amount) return false; 23 | coinBalanceOf[msg.sender] -= amount; 24 | coinBalanceOf[receiver] += amount; 25 | CoinTransfer(msg.sender, receiver, amount); 26 | return true; 27 | } 28 | } 29 | ``` 30 | 如果你有编程基础的话,你不会很难理解它的作用:这是一个合约,为合同的创建者生成10万个令牌,然后允许有足够的余额的任何人发送给他人。这些令牌是最小可交易单位,不能被细分,但最终用户可以表示为100个可再细分成100个子单位的单位,因此拥有单个令牌将占总数的0.01%。如果您的应用程序需要更细粒度的原子分割,那么只需增加初始发行量。 31 | 32 | 在这个例子中,我们将变量“coinBalanceOf”声明为public,这将自动创建一个检查任何账户余额的函数。 33 | ## 编译和部署 34 | 让我们开始吧 35 | ``` 36 | var tokenSource = ' contract token { mapping (address => uint) public coinBalanceOf; event CoinTransfer(address sender, address receiver, uint amount); /* Initializes contract with initial supply tokens to the creator of the contract */ function token(uint supply) { coinBalanceOf[msg.sender] = supply; } /* Very simple trade function */ function sendCoin(address receiver, uint amount) returns(bool sufficient) { if (coinBalanceOf[msg.sender] < amount) return false; coinBalanceOf[msg.sender] -= amount; coinBalanceOf[receiver] += amount; CoinTransfer(msg.sender, receiver, amount); return true; } }' 37 | 38 | var tokenCompiled = eth.compile.solidity(tokenSource) 39 | ``` 40 | 现在我们来设定合同,就像我们在上一节中所做的一样。将“初始供应”更改为要创建的不可分割令牌的数量。如果你想要有可分割的单位,你应该在用户端设置它,但保持用账户的最小单位来表示它。 41 | ``` 42 | var supply = 10000; 43 | var tokenContract = web3.eth.contract(tokenCompiled.token.info.abiDefinition); 44 | var token = tokenContract.new( 45 | supply, 46 | { 47 | from:web3.eth.accounts[0], 48 | data:tokenCompiled.token.code, 49 | gas: 1000000 50 | }, function(e, contract){ 51 | if(!e) { 52 | 53 | if(!contract.address) { 54 | console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined..."); 55 | 56 | } else { 57 | console.log("Contract mined! Address: " + contract.address); 58 | console.log(contract); 59 | } 60 | 61 | } 62 | }) 63 | ``` 64 | ## 在线编译器 65 | 如果您没有安装SolC,可以直接使用在线编译器。将合同代码复制到在线solidity编译器,如果合约上没有错误,您应该看到标有Geth Deploy的文本框。将内容复制到文本文件,以便您可以更改第一行以设置初始供应量,如下所示: 66 | ``` 67 | var supply = 10000; 68 | ``` 69 | 现在您可以将生成的文本粘贴到您的geth窗口。等待三十秒钟,您会看到如下消息: 70 | ``` 71 | Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e 72 | ``` 73 | ## 检查余额来观察货币流动 74 | 如果一切正常,您应该可以通过以下方式查看自己的余额: 75 | ``` 76 | token.coinBalanceOf(eth.accounts[0]) + " tokens" 77 | ``` 78 | 合同一旦发布后,应该拥有10000个令牌。由于没有任何其他定义的方式来发行新的硬币,这些固定令牌都是永远存在的。 79 | 80 | 每当任何人使用您的合约发送硬币时,您可以设置一个观察者来做出反应。以下是您的操作方法: 81 | ``` 82 | var event = token.CoinTransfer({}, '', function(error, result){ 83 | if (!error) 84 | console.log("Coin transfer: " + result.args.amount + " tokens were sent. Balances now are as following: \n Sender:\t" + result.args.sender + " \t" + token.coinBalanceOf.call(result.args.sender) + " tokens \n Receiver:\t" + result.args.receiver + " \t" + token.coinBalanceOf.call(result.args.receiver) + " tokens" ) 85 | }); 86 | ``` 87 | ## 发送货币 88 | 如果你囤积他们,那么这些令牌没有用,所以为了发送给别人,使用这个命令: 89 | ``` 90 | token.sendCoin.sendTransaction(eth.accounts[1], 1000, {from: eth.accounts[0]}) 91 | ``` 92 | 如果朋友在注册商上注册了一个名字,您可以在不知道他们的地址的情况下发送给他: 93 | ``` 94 | token.sendCoin.sendTransaction(registrar.addr("Alice"), 2000, {from: eth.accounts[0]}) 95 | ``` 96 | 请注意,我们的第一个函数**coinBalanceOf**只是直接在合同实例上调用并返回一个值。这是可能的,因为这是一个简单的读取操作,不会导致状态更改,并且在本地和同步执行。我们的第二个函数**sendCoin**需要一个**.sendTransaction()** 调用。由于该功能旨在改变状态(写入操作),所以将其作为交易发送到网络以供矿工打包并包含在规范块中。因此,所有参与者节点的共识状态将充分反映执行事务所导致的状态变化。发件人地址需要作为交易的一部分发送,以资助运行交易所需的花费。现在,等待几分钟然后检查每个账户的余额: 97 | ``` 98 | token.coinBalanceOf.call(eth.accounts[0])/100 + "% of all tokens" 99 | token.coinBalanceOf.call(eth.accounts[1])/100 + "% of all tokens" 100 | token.coinBalanceOf.call(registrar.addr("Alice"))/100 + "% of all tokens" 101 | ``` 102 | ## 改进建议 103 | 现在这个加密货币有很大局限性的,因为只有10000个硬币,所有的都是由货币创建者控制的,但是你可以改变它。你可以通过创建一个交易来奖励找到当前块的旷工: 104 | ``` 105 | mapping (uint => address) miningReward; 106 | function claimMiningReward() { 107 | if (miningReward[block.number] == 0) { 108 | coinBalanceOf[block.coinbase] += 1; 109 | miningReward[block.number] = block.coinbase; 110 | } 111 | } 112 | ``` 113 | 你可以把它修改为其他任何东西:也许是奖励一个找到新的拼图解决方案的人,赢得一场棋的人,安装一个太阳能电池板的人。只要可以以某种方式翻译成一个合同。或者也许你想为你的个人国家创建一个中央银行,所以你可以跟踪工作时间,倾向于或控制财产。在这种情况下,您可能需要添加一个功能,以便银行能够远程冻结资金并在需要时销毁令牌。 114 | 115 | ## 注册你的硬币的名字 116 | 所提到的命令只能工作,因为您在本地计算机上实例化了令牌JavaScript对象。如果您向某人发送令牌,则由于他们没有相同的对象而无法将其移动,也不会知道在何处寻找合同或调用其功能。事实上,如果您重新启动控制台,这些对象将被删除,您一直在处理的合约将永远丢失。那么如何在干净的机器上实例化合同? 117 | 118 | 有两种方法 让我们快速开始,向您的朋友提供您的合同ABI的参: 119 | 考: 120 | ``` 121 | token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at('0x4a4ce7844735c4b6fc66392b200ab6fe007cfca8') 122 | ``` 123 | 只需替换自己的令牌地址的最后一个地址,那么使用此代码段的任何人都可以立即使用您的合同。当然这只适用于这个具体的合同,所以让我们逐步分析一下,看看如何改进这个代码,这样你就可以在任何地方使用它。 124 | 125 | 网络中的所有帐户都被其公共地址引用。但地址长,难以写下来,难以记忆和不变。如果您想要以您的名义生成新帐户,或者升级您的合同代码,则最后一个是特别重要的。为了解决这个问题,有一个默认的名称注册商合同,用于将长地址与简短的,人性化的名称相关联。 126 | 127 | 名称必须仅使用字母数字字符,并且不能包含空格。在未来的版本中,名称注册商可能会实施一个招标过程,以防止名称光占着茅坑,但现在,它是先到先得的原则:只要没有人注册该名称,您可以声明。 128 | 129 | 首先,如果你注册一个名字,那么你最终不需要硬编码的地址。选择一个不错的硬币名称,并尝试为自己预留。首先,选择你的名字: 130 | ``` 131 | var tokenName = "MyFirstCoin" 132 | ``` 133 | 然后,检查你的名字的可用性: 134 | ``` 135 | registrar.addr(tokenName) 136 | ``` 137 | 如果该函数返回“0x00 ..”,您可以向自己声明: 138 | ``` 139 | registrar.reserve.sendTransaction(tokenName, {from: eth.accounts[0]}); 140 | ``` 141 | 等待先前的交易被打包。等待三十秒钟,然后尝试: 142 | ``` 143 | registrar.owner(myName) 144 | ``` 145 | 如果它返回您的地址,则表示您拥有该名称,并且可以将您选择的名称设置为您想要的任何地址: 146 | ``` 147 | registrar.setAddress.sendTransaction(tokenName, token.address, true,{from: eth.accounts[0]}); 148 | ``` 149 | 如果要将其用作个人昵称,可以替换**eth.accounts[0]** 的** token.address**。 150 | 151 | 等待一会儿,让交易被确认,然后测试下: 152 | ``` 153 | registrar.addr("MyFirstCoin") 154 | ``` 155 | 你可以通过简单地输入名字而不是账户来向任何人或者任何合约发送交易: 156 | ``` 157 | eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("MyFirstCoin"), value: web3.toWei(1, "ether")}) 158 | ``` 159 | ** 提示:请勿将registrar.addr同Registrar.owner搞混了。第一个是该名称指向的地址:任何人都可以将名称指向其他任何地方,就像任何人都可以转发到google.com的链接,但只有该名称的所有者可以更改和更新链接。您可以将两者设置为相同的地址。** 160 | 161 | 现在应该返回您的令牌地址,这意味着以前要实例化的代码现在可以使用名称来替换地址。 162 | ``` 163 | token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at(registrar.addr("MyFirstCoin")) 164 | ``` 165 | 这也意味着货币的所有者可以通过将注册商指向新的合同来更新硬币。这当然要求货币持有人信任Registrar.owner(“MyFirstCoin”)设置的所有者 166 | 167 | 当然,这是一个令人不快的大块代码,只是为了允许他人与合同进行交互。有一些将合同ABI上传到网络的方法正在讨论中,以便所有用户需要的仅仅是合同名称。你可以阅读[这些方法](tps://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions#natspec),但它们是实验性的,将来肯定会发生变化。 168 | ## 学到更多 169 | * [元硬币标准](https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs)是为硬币和令牌合约功能名称的标准化而提出的,允许它们自动添加到运用交易的,类似交易所或托管中心的其他ethereum合同中。 170 | * [正式校验](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format#documentation-output)是合同开发商能够声明合同的一些定量的方式,如硬币的总上限。但是尚未实现。 171 | -------------------------------------------------------------------------------- /5.13.4众筹者.md: -------------------------------------------------------------------------------- 1 | ## 众筹你的想法 2 | 有时一个好主意需要大量资金和集体努力。你可以要求捐款,但捐赠者更倾向于给予他们更确定的项目,这些项目将获得牵头和适当的资金。这是一个众所周知的例子,你会建立一个目标和达成目标的最后期限。如果你未完成你的目标,那么捐赠就会被退回,从而减少捐助者的风险。由于代码是开放和可审计的,所以不需要一个集中的可信赖的平台,因此每个人都要支付的费用只是gas费用。 3 | 4 | 众筹通常会给予奖励。这将需要您获取每个人的联系信息并跟踪谁拥有什么。但是,由于你刚刚创建了自己的令牌,为什么不用它来跟踪奖品?捐赠者可以在捐赠后立即拥有东西。他们可以安全地存储,但是如果他们不想要奖品,他们也可以出售或交易。如果您的想法是实物,那么在项目完成后您必须做的所有事情是将产品发送给发回您的令牌的所有人。如果项目是数字化的,则令牌本身可以立即用于用户参与或获得项目的入口。 5 | ## 代码 6 | 这种特殊的人气合约的工作方式是你为你的令牌设定一个汇率,然后捐赠者将立即用他们的ether换取一定比例的令牌。您还将选择资金目标和期限:一旦该期限结束,您可以ping合同,如果达成目标,将把众筹的ether给您,否则可以退给捐助者。即使项目没有达到目标,捐助者也会保留他们的令牌,作为他们帮助你的证明。 7 | ``` 8 | contract token { mapping (address => uint) public coinBalanceOf; function token() {} function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } 9 | 10 | contract Crowdsale { 11 | 12 | address public beneficiary; 13 | uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price; 14 | token public tokenReward; 15 | Funder[] public funders; 16 | event FundTransfer(address backer, uint amount, bool isContribution); 17 | 18 | /* data structure to hold information about campaign contributors */ 19 | struct Funder { 20 | address addr; 21 | uint amount; 22 | } 23 | 24 | /* at initialization, setup the owner */ 25 | function Crowdsale(address _beneficiary, uint _fundingGoal, uint _duration, uint _price, token _reward) { 26 | beneficiary = _beneficiary; 27 | fundingGoal = _fundingGoal; 28 | deadline = now + _duration * 1 minutes; 29 | price = _price; 30 | tokenReward = token(_reward); 31 | } 32 | 33 | /* The function without name is the default function that is called whenever anyone sends funds to a contract */ 34 | function () { 35 | uint amount = msg.value; 36 | funders[funders.length++] = Funder({addr: msg.sender, amount: amount}); 37 | amountRaised += amount; 38 | tokenReward.sendCoin(msg.sender, amount / price); 39 | FundTransfer(msg.sender, amount, true); 40 | } 41 | 42 | modifier afterDeadline() { if (now >= deadline) _ } 43 | 44 | /* checks if the goal or time limit has been reached and ends the campaign */ 45 | function checkGoalReached() afterDeadline { 46 | if (amountRaised >= fundingGoal){ 47 | beneficiary.send(amountRaised); 48 | FundTransfer(beneficiary, amountRaised, false); 49 | } else { 50 | FundTransfer(0, 11, false); 51 | for (uint i = 0; i < funders.length; ++i) { 52 | funders[i].addr.send(funders[i].amount); 53 | FundTransfer(funders[i].addr, funders[i].amount, false); 54 | } 55 | } 56 | suicide(beneficiary); 57 | } 58 | } 59 | ``` 60 | ##设置参数 61 | 在我们进一步之前,让我们从设置人群的参数开始: 62 | ``` 63 | var _beneficiary = eth.accounts[1]; // create an account for this 64 | var _fundingGoal = web3.toWei(100, "ether"); // raises 100 ether 65 | var _duration = 30; // number of minutes the campaign will last 66 | var _price = web3.toWei(0.02, "ether"); // the price of the tokens, in ether 67 | var _reward = token.address; // the token contract address. 68 | ``` 69 | 受益人将收到募集资金的新地址。资金目标是集齐的ether的数量。截止日期是以平均12秒的blocktimes来衡量的,因此默认值约为4周。价格是棘手的:但是只要更改捐赠者每捐一个ether将获得的令牌数量为2。最后奖励应该是您在最后块中创建的令牌合约的地址。 70 | 71 | 在这个例子中,你是在人群中出售所有令牌数量的一半,以换取100个以太。非常仔细地确定这些参数,因为它们将在下一部分指南中发挥非常重要的作用。 72 | ## 部署 73 | 你知道这个练习:如果你使用的是solC编译器,[删除换行符](http://www.textfixer.com/tools/remove-line-breaks.php)并在终端上复制以下命令: 74 | ``` 75 | var crowdsaleCompiled = eth.compile.solidity(' contract token { mapping (address => uint) public coinBalanceOf; function token() {} function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } contract Crowdsale { address public beneficiary; uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price; token public tokenReward; Funder[] public funders; event FundTransfer(address backer, uint amount, bool isContribution); /* data structure to hold information about campaign contributors */ struct Funder { address addr; uint amount; } /* at initialization, setup the owner */ function Crowdsale(address _beneficiary, uint _fundingGoal, uint _duration, uint _price, token _reward) { beneficiary = _beneficiary; fundingGoal = _fundingGoal; deadline = now + _duration * 1 minutes; price = _price; tokenReward = token(_reward); } /* The function without name is the default function that is called whenever anyone sends funds to a contract */ function () { Funder f = funders[++funders.length]; f.addr = msg.sender; f.amount = msg.value; amountRaised += f.amount; tokenReward.sendCoin(msg.sender, f.amount/price); FundTransfer(f.addr, f.amount, true); } modifier afterDeadline() { if (now >= deadline) _ } /* checks if the goal or time limit has been reached and ends the campaign */ function checkGoalReached() afterDeadline { if (amountRaised >= fundingGoal){ beneficiary.send(amountRaised); FundTransfer(beneficiary, amountRaised, false); } else { FundTransfer(0, 11, false); for (uint i = 0; i < funders.length; ++i) { funders[i].addr.send(funders[i].amount); FundTransfer(funders[i].addr, funders[i].amount, false); } } suicide(beneficiary); } }'); 76 | 77 | var crowdsaleContract = web3.eth.contract(crowdsaleCompiled.Crowdsale.info.abiDefinition); 78 | var crowdsale = crowdsaleContract.new( 79 | _beneficiary, 80 | _fundingGoal, 81 | _duration, 82 | _price, 83 | _reward, 84 | { 85 | from:web3.eth.accounts[0], 86 | data:crowdsaleCompiled.Crowdsale.code, 87 | gas: 1000000 88 | }, function(e, contract){ 89 | if(!e) { 90 | 91 | if(!contract.address) { 92 | console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined..."); 93 | 94 | } else { 95 | console.log("Contract mined! Address: " + contract.address); 96 | console.log(contract); 97 | } 98 | 99 | } }) 100 | ``` 101 | 如果您正在使用在线编译器,将合约代码复制到在线solidity编译器,然后获取标记为Geth Deploy的文本框的内容。由于您已经设置了参数,因此您不需要更改任何文本,只需将生成的文本粘贴到您的geth窗口中即可。 102 | 103 | 等待三十秒钟,您会看到如下消息: 104 | ``` 105 | Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e 106 | ``` 107 | 如果您收到该警报,那么您的代码应该在线。你可以随时仔细检查一下: 108 | ``` 109 | eth.getCode(crowdsale.address) 110 | ``` 111 | 现在为您创建的合约提供必要的令牌,以便自动将奖励分配给贡献者! 112 | ``` 113 | token.sendCoin.sendTransaction(crowdsale.address, 5000,{from: eth.accounts[0]}) 114 | ``` 115 | 打包交易后,您可以通过以下方式检查人群地址拥有的令牌数量以及所有其他变量: 116 | ``` 117 | "Current crowdsale must raise " + web3.fromWei(crowdsale.fundingGoal.call(), "ether") + " ether in order to send it to " + crowdsale.beneficiary.call() + "." 118 | ``` 119 | ## 设置观察者 120 | 您希望在人群收到新的资金时收到警报,因此粘贴此代码: 121 | ``` 122 | var event = crowdsale.FundTransfer({}, '', function(error, result){ 123 | if (!error) 124 | 125 | if (result.args.isContribution) { 126 | console.log("\n New backer! Received " + web3.fromWei(result.args.amount, "ether") + " ether from " + result.args.backer ) 127 | 128 | console.log( "\n The current funding at " +( 100 * crowdsale.amountRaised.call() / crowdsale.fundingGoal.call()) + "% of its goals. Funders have contributed a total of " + web3.fromWei(crowdsale.amountRaised.call(), "ether") + " ether."); 129 | 130 | var timeleft = Math.floor(Date.now() / 1000)-crowdsale.deadline(); 131 | if (timeleft>3600) { console.log("Deadline has passed, " + Math.floor(timeleft/3600) + " hours ago") 132 | } else if (timeleft>0) { console.log("Deadline has passed, " + Math.floor(timeleft/60) + " minutes ago") 133 | } else if (timeleft>-3600) { console.log(Math.floor(-1*timeleft/60) + " minutes until deadline") 134 | } else { console.log(Math.floor(-1*timeleft/3600) + " hours until deadline") 135 | } 136 | 137 | } else { 138 | console.log("Funds transferred from crowdsale account: " + web3.fromWei(result.args.amount, "ether") + " ether to " + result.args.backer ) 139 | } 140 | 141 | }); 142 | ``` 143 | ## 注册合同 144 | 你现在已经设置好了 任何人现在可以通过简单地发送ether到crowdsale地址来贡献,但为了使其更简单,让我们注册您的销售名称。首先,为你的crowdsale选一个名字: 145 | ``` 146 | var name = "mycrowdsale" 147 | ``` 148 | 检查是否可用并注册: 149 | ``` 150 | registrar.addr(name) 151 | registrar.reserve.sendTransaction(name, {from: eth.accounts[0]}); 152 | ``` 153 | 等待先前的交易被打包,然后: 154 | ``` 155 | registrar.setAddress.sendTransaction(name, crowdsale.address, true,{from: eth.accounts[0]}); 156 | ``` 157 | ## 为crowdsale做贡献 158 | 159 | 为crowdsale做贡献非常简单,甚至不需要实例化合同。这是因为crowdsale响应简单的crowdsale存款,所以向crowdsale发送ether的任何人都将自动获得奖励。任何人都可以通过简单的执行这个命令来做出贡献: 160 | ``` 161 | var amount = web3.toWei(5, "ether") // decide how much to contribute 162 | 163 | eth.sendTransaction({from: eth.accounts[0], to: crowdsale.address, value: amount, gas: 1000000}) 164 | ``` 165 | 或者,如果你想让别人发送它,他们甚至可以使用名称注册商来做贡献: 166 | ``` 167 | eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("mycrowdsale"), value: amount, gas: 500000}) 168 | ``` 169 | 现在等待一分钟,您可以通过执行以下命令来检查合同是否收到ether: 170 | ``` 171 | web3.fromWei(crowdsale.amountRaised.call(), "ether") + " ether" 172 | token.coinBalanceOf.call(eth.accounts[0]) + " tokens" 173 | token.coinBalanceOf.call(crowdsale.address) + " tokens" 174 | ``` 175 | ## 收回资金 176 | 一旦到了截止日期,有人必须唤起合约,将资金发送给受益人或回到资助者(如果失败)。发生这种情况是因为ethereum没有一个有效的循环或计时器等等,所以任何未来的交易必须由某人ping。 177 | ``` 178 | crowdsale.checkGoalReached.sendTransaction({from:eth.accounts[0], gas: 2000000}) 179 | ``` 180 | 您可以使用以下代码来检查您的帐户: 181 | ``` 182 | web3.fromWei(eth.getBalance(eth.accounts[0]), "ether") + " ether" 183 | web3.fromWei(eth.getBalance(eth.accounts[1]), "ether") + " ether" 184 | token.coinBalanceOf.call(eth.accounts[0]) + " tokens" 185 | token.coinBalanceOf.call(eth.accounts[1]) + " tokens" 186 | ``` 187 | 一旦完成了工作,crowdsale实例被设置为自我毁灭,所以如果截止日期结束,每个人都获得奖品。合约不再存在,你运行下面代码来验证: 188 | ``` 189 | eth.getCode(crowdsale.address) 190 | ``` 191 | 所以你获得了100个ether,并成功地将你的原始硬币分配给了众多的捐助者。接下来你能做些什么呢? 192 | -------------------------------------------------------------------------------- /5.13.5民主DAO.md: -------------------------------------------------------------------------------- 1 | ## 民主DAO 2 | 到目前为止,您已经创建了一个可交易的令牌,并且您成功地将其分发给愿意帮助筹集100个ether的所有人。这一切都很有趣,但这些令牌究竟是什么呢?为什么有人想要拥有它或用它交易任何其他有价值的东西?如果你能说服你的新令牌是下一个有价值的货币,可能其他人会想要它,但到目前为止,你的令牌本身没有价值。我们将通过创建您的第一个分散式自治组织或DAO来改变这一点。 3 | 4 | 将DAO视为一个国家的体制,一个政府的行政部门,或者也许像一个机构的机器人经理。DAO收到您的组织募集的资金,保持安全,并使用它来资助任何需要资金的会员。机器人是清廉的,永远不会欺骗银行,永远不会制造秘密的计划,从来不会把这些钱用于未经其所有者投票的东西。DAO永远不会消失,永远不会逃跑,不能由其本国公民以外的任何人控制。 5 | 6 | 我们使用crowdsale分发的令牌是唯一需要的公民文件。任何持有任何令牌的人都可以创建投票和投票。与公司中的股东类似,令牌可以在公开市场上交易,选票与选民持有的令牌数成正比。 7 | 8 | 花一点时间来思考这革命性的可能性,现在你可以用下面的100行代码自己做一下 9 | ## 代码 10 | ``` 11 | contract token { mapping (address => uint) public coinBalanceOf; function token() { } function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } 12 | 13 | 14 | contract Democracy { 15 | 16 | uint public minimumQuorum; 17 | uint public debatingPeriod; 18 | token public voterShare; 19 | address public founder; 20 | Proposal[] public proposals; 21 | uint public numProposals; 22 | 23 | event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description); 24 | event Voted(uint proposalID, int position, address voter); 25 | event ProposalTallied(uint proposalID, int result, uint quorum, bool active); 26 | 27 | struct Proposal { 28 | address recipient; 29 | uint amount; 30 | bytes32 data; 31 | string description; 32 | uint creationDate; 33 | bool active; 34 | Vote[] votes; 35 | mapping (address => bool) voted; 36 | } 37 | 38 | struct Vote { 39 | int position; 40 | address voter; 41 | } 42 | 43 | function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) { 44 | founder = msg.sender; 45 | voterShare = token(_voterShareAddress); 46 | minimumQuorum = _minimumQuorum || 10; 47 | debatingPeriod = _debatingPeriod * 1 minutes || 30 days; 48 | } 49 | 50 | 51 | function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) { 52 | if (voterShare.coinBalanceOf(msg.sender)>0) { 53 | proposalID = proposals.length++; 54 | Proposal p = proposals[proposalID]; 55 | p.recipient = _recipient; 56 | p.amount = _amount; 57 | p.data = _data; 58 | p.description = _description; 59 | p.creationDate = now; 60 | p.active = true; 61 | ProposalAdded(proposalID, _recipient, _amount, _data, _description); 62 | numProposals = proposalID+1; 63 | } 64 | } 65 | 66 | function vote(uint _proposalID, int _position) returns (uint voteID){ 67 | if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) { 68 | Proposal p = proposals[_proposalID]; 69 | if (p.voted[msg.sender] == true) return; 70 | voteID = p.votes.length++; 71 | p.votes[voteID] = Vote({position: _position, voter: msg.sender}); 72 | p.voted[msg.sender] = true; 73 | Voted(_proposalID, _position, msg.sender); 74 | } 75 | } 76 | 77 | function executeProposal(uint _proposalID) returns (int result) { 78 | Proposal p = proposals[_proposalID]; 79 | /* Check if debating period is over */ 80 | if (now > (p.creationDate + debatingPeriod) && p.active){ 81 | uint quorum = 0; 82 | /* tally the votes */ 83 | for (uint i = 0; i < p.votes.length; ++i) { 84 | Vote v = p.votes[i]; 85 | uint voteWeight = voterShare.coinBalanceOf(v.voter); 86 | quorum += voteWeight; 87 | result += int(voteWeight) * v.position; 88 | } 89 | /* execute result */ 90 | if (quorum > minimumQuorum && result > 0 ) { 91 | p.recipient.call.value(p.amount)(p.data); 92 | p.active = false; 93 | } else if (quorum > minimumQuorum && result < 0) { 94 | p.active = false; 95 | } 96 | ProposalTallied(_proposalID, result, quorum, p.active); 97 | } 98 | } 99 | } 100 | ``` 101 | 有很多事情要做,但它比看起来更简单。您的组织规则非常简单:任何有至少一个令牌的人都可以创建从国家帐户发送资金的提案。经过一周的辩论和投票,如果已经获得总共100个令牌或更多的票数,并且比反对更多的批准,这些资金将被发送。如果法定人数没有得到满足,或者结果不分胜负,那么投票将被保留,直到解决。否则,该提案被锁定并保存为历史记录。 102 | 103 | 所以让我们回顾一下这是什么意思:在最后两节中,你创建了10000个令牌,将其中的1000个发送给另一个你所控制的帐户,2,000个给一个叫Alice的朋友,并通过crowdsale分发了5,000个。这意味着您不再控制DAO中超过50%的投票,如果Alice和社区团结在一起,他们可以对迄今为止所募集的100个ether的支出做出决定。这正是民主应该如何运作的。如果你不想成为你国家的一部分,你唯一可以做的就是在一个分散的交换中出售自己的令牌,并选择退出,但是你不能阻止别人这样做。 104 | ## 建立你的组织 105 | 106 | 所以打开你的控制台,让我们准备好最终把你的国家放在网络上。首先,我们设置正确的参数,小心挑选: 107 | ``` 108 | var _voterShareAddress = token.address; 109 | var _minimumQuorum = 10; // Minimun amount of voter tokens the proposal needs to pass 110 | var _debatingPeriod = 60; // debating period, in minutes; 111 | ``` 112 | 使用这些默认参数,任何具有任何令牌的人都可以提出如何花费组织的钱的建议。该提案有1小时的辩论时间,如果它有所有令牌中至少0.1%的票数,并且支持比反对多,它将被通过。仔细选择这些参数,因为您将来无法更改它们。 113 | ``` 114 | var daoCompiled = eth.compile.solidity('contract token { mapping (address => uint) public coinBalanceOf; function token() { } function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } contract Democracy { uint public minimumQuorum; uint public debatingPeriod; token public voterShare; address public founder; Proposal[] public proposals; uint public numProposals; event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description); event Voted(uint proposalID, int position, address voter); event ProposalTallied(uint proposalID, int result, uint quorum, bool active); struct Proposal { address recipient; uint amount; bytes32 data; string description; uint creationDate; bool active; Vote[] votes; mapping (address => bool) voted; } struct Vote { int position; address voter; } function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) { founder = msg.sender; voterShare = token(_voterShareAddress); minimumQuorum = _minimumQuorum || 10; debatingPeriod = _debatingPeriod * 1 minutes || 30 days; } function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) { if (voterShare.coinBalanceOf(msg.sender)>0) { proposalID = proposals.length++; Proposal p = proposals[proposalID]; p.recipient = _recipient; p.amount = _amount; p.data = _data; p.description = _description; p.creationDate = now; p.active = true; ProposalAdded(proposalID, _recipient, _amount, _data, _description); numProposals = proposalID+1; } else { return 0; } } function vote(uint _proposalID, int _position) returns (uint voteID){ if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) { Proposal p = proposals[_proposalID]; if (p.voted[msg.sender] == true) return; voteID = p.votes.length++; Vote v = p.votes[voteID]; v.position = _position; v.voter = msg.sender; p.voted[msg.sender] = true; Voted(_proposalID, _position, msg.sender); } else { return 0; } } function executeProposal(uint _proposalID) returns (int result) { Proposal p = proposals[_proposalID]; /* Check if debating period is over */ if (now > (p.creationDate + debatingPeriod) && p.active){ uint quorum = 0; /* tally the votes */ for (uint i = 0; i < p.votes.length; ++i) { Vote v = p.votes[i]; uint voteWeight = voterShare.coinBalanceOf(v.voter); quorum += voteWeight; result += int(voteWeight) * v.position; } /* execute result */ if (quorum > minimumQuorum && result > 0 ) { p.recipient.call.value(p.amount)(p.data); p.active = false; } else if (quorum > minimumQuorum && result < 0) { p.active = false; } } ProposalTallied(_proposalID, result, quorum, p.active); } }'); 115 | 116 | var democracyContract = web3.eth.contract(daoCompiled.Democracy.info.abiDefinition); 117 | 118 | var democracy = democracyContract.new( 119 | _voterShareAddress, 120 | _minimumQuorum, 121 | _debatingPeriod, 122 | { 123 | from:web3.eth.accounts[0], 124 | data:daoCompiled.Democracy.code, 125 | gas: 3000000 126 | }, function(e, contract){ 127 | if(!e) { 128 | 129 | if(!contract.address) { 130 | console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined..."); 131 | 132 | } else { 133 | console.log("Contract mined! Address: " + contract.address); 134 | console.log(contract); 135 | } 136 | 137 | } 138 | }) 139 | ``` 140 | 如果您正在使用在线编译器,将合同代码复制到在线solidity编译器,然后获取标记为Geth Deploy文本框的内容。由于您已经设置了参数,因此您不需要更改任何文本,只需将生成的文本粘贴到您的geth窗口中即可。 141 | 142 | 等一会儿,直到矿工将其打包。这将耗费大约850k Gas。一旦被打包,现在是时间来实例化并设置它,将其指向您之前创建的令牌合约的正确地址。 143 | 144 | 如果一切顺利,您可以通过执行下面的字符串来查看整个组织: 145 | ``` 146 | "This organization has " + democracy.numProposals() + " proposals and uses the token at the address " + democracy.voterShare() ; 147 | ``` 148 | 如果一切都设置好了,那么你的DAO应该返回一个数量为0的提案和一个标记为“founder”的地址。虽然仍然没有提案,DAO的创始人可以将令牌的地址更改为任何需要的地址。 149 | 150 | ## 注册您的组织名称 151 | 我们还为您的合同注册一个名称,以便轻松访问(不要忘记在预订之前使用`registrar.addr(“nameYouWant”)`检查您的名称可用性!) 152 | ``` 153 | var name = "MyPersonalDemocracy" 154 | registrar.reserve.sendTransaction(name, {from: eth.accounts[0]}) 155 | var democracy = eth.contract(daoCompiled.Democracy.info.abiDefinition).at(democracy.address); 156 | democracy.setup.sendTransaction(registrar.addr("MyFirstCoin"),{from:eth.accounts[0]}) 157 | ``` 158 | 等待先前的交易被打包,然后: 159 | ``` 160 | registrar.setAddress.sendTransaction(name, democracy.address, true,{from: eth.accounts[0]}); 161 | ``` 162 | ## 民主监控者 163 | ``` 164 | var event = democracy.ProposalAdded({}, '', function(error, result){ 165 | if (!error) 166 | console.log("New Proposal #"+ result.args.proposalID +"!\n Send " + web3.fromWei(result.args.amount, "ether") + " ether to " + result.args.recipient.substring(2,8) + "... for " + result.args.description ) 167 | }); 168 | var eventVote = democracy.Voted({}, '', function(error, result){ 169 | if (!error) 170 | var opinion = ""; 171 | if (result.args.position > 0) { 172 | opinion = "in favor" 173 | } else if (result.args.position < 0) { 174 | opinion = "against" 175 | } else { 176 | opinion = "abstaining" 177 | } 178 | 179 | console.log("Vote on Proposal #"+ result.args.proposalID +"!\n " + result.args.voter + " is " + opinion ) 180 | }); 181 | var eventTally = democracy.ProposalTallied({}, '', function(error, result){ 182 | if (!error) 183 | var totalCount = ""; 184 | if (result.args.result > 1) { 185 | totalCount = "passed" 186 | } else if (result.args.result < 1) { 187 | totalCount = "rejected" 188 | } else { 189 | totalCount = "a tie" 190 | } 191 | console.log("Votes counted on Proposal #"+ result.args.proposalID +"!\n With a total of " + Math.abs(result.args.result) + " out of " + result.args.quorum + ", proposal is " + totalCount + ". Proposal is " + (result.args.active? " still on the floor" : "archived") ) 192 | }); 193 | ``` 194 | ## 与DAO交互 195 | 在你对自己想要的满意之后,现在是把你从众筹中获得的所有的东西拿到你的新组织的时候了 196 | ``` 197 | eth.sendTransaction({from: eth.accounts[1], to: democracy.address, value: web3.toWei(100, "ether")}) 198 | ``` 199 | 这只需要一分钟,你的国家已经准备好了!现在,作为首要任务,您的组织需要一个不错的标志,但除非您是设计师,否则您不知道如何做到这一点。为了论证的缘故,我们假设你发现你的朋友鲍勃是一位伟大的设计师,他愿意只要10个ether来做这件事,所以你想提出聘请他。 200 | ``` 201 | recipient = registrar.addr("bob"); 202 | amount = web3.toWei(10, "ether"); 203 | shortNote = "Logo Design"; 204 | 205 | democracy.newProposal.sendTransaction( recipient, amount, '', shortNote, {from: eth.accounts[0], gas:1000000}) 206 | ``` 207 | 一分钟后,任何人都可以通过执行以下命令来检查提案的收件人和金额: 208 | ``` 209 | "This organization has " + (Number(democracy.numProposals())+1) + " pending proposals"; 210 | ``` 211 | ## 关注组织 212 | 与大多数政府不同,贵国政府完全透明,易于编程。作为一个小型示范,这里有一段代码,列出所有当前的提案和打印他们的内容和目的: 213 | ``` 214 | function checkAllProposals() { 215 | console.log("Country Balance: " + web3.fromWei( eth.getBalance(democracy.address), "ether") ); 216 | for (i = 0; i< (Number(democracy.numProposals())); i++ ) { 217 | var p = democracy.proposals(i); 218 | var timeleft = Math.floor(((Math.floor(Date.now() / 1000)) - Number(p[4]) - Number(democracy.debatingPeriod()))/60); 219 | console.log("Proposal #" + i + " Send " + web3.fromWei( p[1], "ether") + " ether to address " + p[0].substring(2,6) + " for "+ p[3] + ".\t Deadline:"+ Math.abs(Math.floor(timeleft)) + (timeleft>0?" minutes ago ":" minutes left ") + (p[5]? " Active":" Archived") ); 220 | } 221 | } 222 | 223 | checkAllProposals(); 224 | ``` 225 | 一个公民可以很容易地写一个机器人,定期ping那个blockchain,然后公布所提出的任何新提案,保证透明度。 226 | 227 | 现在当然你希望其他人能够对你的建议投票。您可以查看crowdsale教程关于注册合约APP的最佳方式,以便所有用户需要是一个名称,但现在让我们使用更简单的版本。任何人都应该能够使用下面的命令在计算机上实例化你的国家的本地副本: 228 | ``` 229 | democracy = eth.contract( [{ constant: true, inputs: [{ name: '', type: 'uint256' } ], name: 'proposals', outputs: [{ name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' }, { name: 'data', type: 'bytes32' }, { name: 'descriptionHash', type: 'bytes32' }, { name: 'creationDate', type: 'uint256' }, { name: 'numVotes', type: 'uint256' }, { name: 'quorum', type: 'uint256' }, { name: 'active', type: 'bool' } ], type: 'function' }, { constant: false, inputs: [{ name: '_proposalID', type: 'uint256' } ], name: 'executeProposal', outputs: [{ name: 'result', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'debatingPeriod', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'numProposals', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'founder', outputs: [{ name: '', type: 'address' } ], type: 'function' }, { constant: false, inputs: [{ name: '_proposalID', type: 'uint256' }, { name: '_position', type: 'int256' } ], name: 'vote', outputs: [{ name: 'voteID', type: 'uint256' } ], type: 'function' }, { constant: false, inputs: [{ name: '_voterShareAddress', type: 'address' } ], name: 'setup', outputs: [ ], type: 'function' }, { constant: false, inputs: [{ name: '_recipient', type: 'address' }, { name: '_amount', type: 'uint256' }, { name: '_data', type: 'bytes32' }, { name: '_descriptionHash', type: 'bytes32' } ], name: 'newProposal', outputs: [{ name: 'proposalID', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'minimumQuorum', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { inputs: [ ], type: 'constructor' } ] ).at(registrar.addr('MyPersonalCountry')) 230 | ``` 231 | 那么任何拥有任何你的令牌的人都可以通对投票表决: 232 | ``` 233 | var proposalID = 0; 234 | var position = -1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum 235 | democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000}); 236 | 237 | var proposalID = 1; 238 | var position = 1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum 239 | democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000}); 240 | ``` 241 | 除非您更改代码中的基本参数,否则任何提案至少需要一周时间才能被执行。之后,即使是非公民,也可以要求投票和执行的提案。投票在当时计算和加权,如果提案被接受,则ether将立即发送,并将提案归档。如果票数结束时不分上下或最低法定人数未达成,表决将保持开放,直到僵局解决。如果它丢失了,那么它被存档,不能再投票了。 242 | ``` 243 | var proposalID = 1; 244 | democracy.executeProposal.sendTransaction(proposalID, {from: eth.accounts[0], gas: 1000000}); 245 | ``` 246 | 如果提案通过,那么你应该可以看到鲍勃的ether到达他的地址: 247 | ``` 248 | web3.fromWei(eth.getBalance(democracy.address), "ether") + " ether"; 249 | web3.fromWei(eth.getBalance(registrar.addr("bob")), "ether") + " ether"; 250 | ``` 251 | 尝试自己: 这是一个非常简单的民主合约,有很大改善空间。目前,所有提案都有相同的讨论时间,并以直接投票和简单多数获胜。你可以改变一下,这样会有一些情况,根据提议的数额,辩论可能会更长,还是需要更大的数目?还要考虑一些公民不需要对每个问题投票的方式,并可以临时将其投票授权给特别代表。您可能还注意到,我们为每个提案添加了一个细微的描述。这可以用作提案的标题,或者可以是详细描述其的较大文档的哈希。 252 | 253 | ## 我们去探索吧! 254 | 你已经到了本教程的最后,但它只是一个伟大的冒险的开始。回头看看你的成就:你创造了一个活的,谈话的机器人,你自己的加密货币,通过不可靠的众筹来募集资金,并用它来启动你自己的个人民主组织。 255 | 256 | 为了简单起见,我们只使用你所创造的民主组织来发送ether,他是ethereum中天生的货币。虽然这对一些人来说可能是足够好的,但这只是掀开可以做的事情的的面纱。在ethereum网络中,合约具有与任何普通用户相同的权利,这意味着您的组织可以执行您从自己的帐户执行的任何交易。 257 | 258 | ## 接下来会发生什么? 259 | 260 | * 您开始创建的greeter合约可以改进,以便为其服务收费,并可将这些资金纳入DAO。 261 | * 您仍然控制的令牌可以在分散的交易所上销售,也可以交易货物和服务,以进一步开发第一份合约并扩大组织。 262 | * 您的DAO可以在名称注册商上拥有自己的名称,然后更改其重定向的位置,以便在令牌持有人批准时进行更新。 263 | * 该组织不仅可以持有ethers,而且还可以拥有任何一种ethereum上产生的其他货币,包括价值与比特币或美元挂钩的资产。 264 | 265 | * DAO可以被编程为允许具有多个交易的提案,一些提案被预定在未来。它也可以拥有其他DAO的股份,这意味着它可以投票给更大的组织或成为DAO联合会的一部分。 266 | * 令牌合约可以重新编程,以保持ether或持有其他令牌并将其分配给令牌持有者。这将把令牌的价值与其他资产的价值联系起来,所以通过简单地将资金转移到令牌地址就能实现分红。 267 | 268 | 这一切都意味着你创造的这个小小的社会可以增长,从第三方获得资金,支付经常性工资,拥有任何种类的密码资产,甚至使用crowdsales资助其活动。所有这些都具有完全的透明度,完整的责任感和完全排除任何人为干扰。当网络存活的时候,合同将完全执行他们被创建用来执行的代码,无一例外地执行。 269 | 270 | 那么你的合同是什么?它会成为一个国家,一家公​​司,一个非营利组织?你的代码会做什么? 271 | 272 | 这取决于你。 273 | -------------------------------------------------------------------------------- /5.13合约教程.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | 3 | 既然你已经掌握了如何开始和如何发送gether的基础知识,现在是时候开始接触让ethereum脱颖而出特质:智能合约。智能合约是BlockChain上存在的代码块,当被告知如何做的时候会准确执行指令。他们可以阅读其他合约,作出决定,发送ether以及执行其他合约。只要整个网络存在,、合约会存在并运行,只有在用尽了gas或被编程为自毁的情况下才会停止。 4 | 5 | 你可以用合约做什么?你几乎可以做任何事情,但是对于这个指南,我们来做一些简单的事情:你将通过众筹来获得资金,如果成功,将提供一个完全透明和民主的组织,只能服从自己的公民,永远不会摆脱其体制,不能被审查或关闭。而且所有这些都在不到300行的代码中实现。 6 | 7 | 所以现在开始吧。 8 | -------------------------------------------------------------------------------- /5.1账户类型与交易.md: -------------------------------------------------------------------------------- 1 | ## 帐户类型和交易 2 | Ethereum有两种类型的帐户: 3 | * 正常或外部控制的帐户 4 | * 合同,即代码片段,可以看成一个类。 5 | 6 | 这两种类型的帐户都具有ether余额。 7 | 8 | 两种类型的帐户都可以触发交易,尽管合约仅针对其收到的其他交易触发交易。因此,通过外部控制账户发起的交易,所有ethereum 区块链上的行为都被唤起。 9 | 10 | 最简单的交易是ether传输交易。但在我们进入之前,你应该阅读帐目,也可以在采矿时阅读。 11 | -------------------------------------------------------------------------------- /5.2ether转移.md: -------------------------------------------------------------------------------- 1 | ## ether转移 2 | 3 | 假设你用作发送者的帐户有足够的资金,发送ether就没那么容易了。这也是为什么你应该小心这个!你被警告了。 4 | 5 | `eth.sendTransaction({from: '0x036a03fc47084741f83938296a1c8ef67f6e34fa', to: '0xa8ade7feab1ece71446bed25fa0cf6745c19c3d5', value: web3.toWei(1, "ether")})` 6 | 7 | 请注意`value`的单位转换。交易值以最细粒度的单位weis表示。如果要使用其他单元(如上例的ether),请使用`web3.toWei`进行转换。 8 | 9 | 此外,请注意,从源帐户扣除的金额将略高于目标账户的金额,这是已经规定好的。差异是一个小的交易费用,稍后再讨论。 10 | 11 | 合约可以像外部控制的账户一样收到转账,但也可以收到更复杂的事务,实际上是运行(部分)代码并更新其状态。为了理解这些交易,需要对合约有根本的理解。 12 | -------------------------------------------------------------------------------- /5.3制定合约.md: -------------------------------------------------------------------------------- 1 | ## 制定合约 2 | 合同以Ethereum特有的二进制格式(Ethereum Virtual Machine(= EVM)字节码)生成在块上。然而,合同通常用更高级的语言写成,如[solidity](https://github.com/ethereum/wiki/wiki/Solidity-Tutorial),然后编译成将被上传到blockchain上的字节码。 3 | 4 | 请注意还有其他高级语言的存在,如[serpent](https://github.com/ethereum/wiki/wiki/Serpent)和[LLL](https://github.com/ethereum/cpp-ethereum/wiki)。Legacy Mutan(早期的类C语言)不在被官方支持。 5 | 6 | ## 语言资源 7 | ### Solidity 8 | #### 文档和教程 9 | 10 | * [Ethereum wiki tutorial](https://github.com/ethereum/wiki/wiki/Solidity-Tutorial) 11 | * [Solidity FAQ - Ethereum forum](https://forum.ethereum.org/discussion/1460/solidity-faq) 12 | * [The Solidity Programming Language · ethereum/wiki](https://github.com/ethereum/wiki/wiki/The-Solidity-Programming-Language) 13 | * [Ethereum ÐΞVcon-0: Solidity, Vision and Roadmap - YouTube Video](https://www.youtube.com/watch?v=DIqGDNPO5YM) 14 | * [Dapps for beginners](https://dappsforbeginners.wordpress.com/) 15 | * [Tutorial 1](https://forum.ethereum.org/discussion/1634/tutorial-1-your-first-contract/p1 ) 16 | * [Tutorial 2](https://forum.ethereum.org/discussion/1635/tutorial-2-rainbow-coin) 17 | * [Tutorial 3 (JavaScript API for Ethereum](https://forum.ethereum.org/discussion/1636/tutorial-3-introduction-to-the-javascript-api)(Outdated) 18 | * [Solidity tutorial 1 by Eris Industries](https://eng.erisindustries.com/tutorials/2015/03/11/solidity-1/) 19 | * [Dapp tutorials by Andreas Olofsson (Eris Industries)](https://www.youtube.com/playlist?list=PL_kFomDrqPoZBu5uxd8OBGColQPYbuz3i) 20 | * [Eris Solidity resources](https://github.com/eris-ltd/solidity-resources) 21 | 22 | 23 | ### 示例 24 | * [a dapp listing](https://github.com/ethereum/wiki/wiki/FAQ#where-can-i-find-example-%C3%90apps) 25 | * [Solidity Contracts on Ethereum - Ether.Fund](https://ether.fund/contracts/solidity) 26 | * [Ethereum dapp bin](https://github.com/ethereum/dapp-bin/) 27 | * [Solidity Standard Library](https://github.com/ethereum/wiki/wiki/Solidity-standard-library) 28 | * [Whisper chat Dapp written in meteor](https://github.com/ethereum/meteor-dapp-whisper-chat-client/tree/master/dist/deploy) 29 | * [order statistic tree by Conrad Bars](https://github.com/drcode/ethereum-order-statistic-treem) 30 | 31 | ### 编译器 32 | * [Solidity realtime compiler](https://chriseth.github.io/browser-solidity/) 33 | 34 | ### Serpent 35 | * [source on github](https://github.com/ethereum/serpent) 36 | * [serpent language spec](https://github.com/ethereum/wiki/wiki/Serpent) 37 | 38 | ## 智能合约/Dapp开发环境和框架 39 | 40 | * [Mix standalone IDE](https://github.com/ethereum/wiki/wiki/Mix:-The-DApp-IDE) by ETHDEV 41 | * in-browser [Cosmo](http://meteor-dapp-cosmo.meteor.com/) that connects to `geth` via RPC. By Nick Dodson 42 | * [embark framework](https://github.com/iurimatias/embark-framework/) by Iuri Mathias 43 | * [truffle](https://github.com/ConsenSys/truffle) by Tim Coulter 44 | -------------------------------------------------------------------------------- /5.4编译合约.md: -------------------------------------------------------------------------------- 1 | ## 编译合约 2 | 合约以Ethereum特有的二进制格式(Ethereum Virtual Machine(= EVM)字节码)生成在blockchain上。然而,合约通常用更高级的语言来写,如[solidity](https://github.com/ethereum/wiki/wiki/Solidity-Tutorial),然后编译成将被上传至blockchain的字节码。 3 | 4 | 对于Frontier版本,`geth`通过系统调用`solc`来支持[solidity编译](https://github.com/ethereum/cpp-ethereum/tree/develop/solc),它是Christian R.和Lefteris K写的命令行solidity 编译器。您可以尝试[Solidity实时编译器](https://chriseth.github.io/browser-solidity/)(Christian R)或[Cosmo](http://meteor-dapp-cosmo.meteor.com/)或[Mix](https://github.com/ethereum/wiki/wiki/Mix:-The-DApp-IDE)。 5 | 6 | 如果你想启动你的geth节点,你可以先检查下solidity编译器是否可用,假如不可用,则会出现下面的情况: 7 | ``` 8 | > eth.compile.solidity("") 9 | eth_compileSolidity method not available: solc (solidity compiler) not found 10 | at InvalidResponse (:-57465:-25) 11 | at send (:-115373:-25) 12 | at solidity (:-104109:-25) 13 | at :1:1 14 | ``` 15 | 找到一种方式安装`solc`后,确保它在路径中。如果[eth.getCompilers()](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgetcompilers)仍然找不到(返回一个空数组),您可以在命令行上使用`solc`标志设置`solc`可执行文件的自定义路径。 16 | 17 | `geth --datadir ~/frontier/00 --solc /usr/local/bin/solc --natspec 18 | ` 19 | 20 | 您还可以通过控制台在运行时设置此选项: 21 | ``` 22 | > admin.setSolc("/usr/local/bin/solc") 23 | solc v0.9.32 24 | Solidity Compiler: /usr/local/bin/solc 25 | Christian and Lefteris (c) 2014-2015 26 | true 27 | ``` 28 | 29 | 下面我们使用简单的智能合约作例子: 30 | ``` 31 | > source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }" 32 | ``` 33 | 这个合同提供了一个一元的方法:一个正整数`a`传入并调用,它返回`a * 7`。 34 | 35 | 您可以geth使用[eth.compile.solidity](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcompilesolidity)在JS控制台中编译solidity代码: 36 | ``` 37 | > contract = eth.compile.solidity(source).test 38 | { 39 | code: '605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056', 40 | info: { 41 | language: 'Solidity', 42 | languageVersion: '0', 43 | compilerVersion: '0.9.13', 44 | abiDefinition: [{ 45 | constant: false, 46 | inputs: [{ 47 | name: 'a', 48 | type: 'uint256' 49 | } ], 50 | name: 'multiply', 51 | outputs: [{ 52 | name: 'd', 53 | type: 'uint256' 54 | } ], 55 | type: 'function' 56 | } ], 57 | userDoc: { 58 | methods: { 59 | } 60 | }, 61 | developerDoc: { 62 | methods: { 63 | } 64 | }, 65 | source: 'contract test { function multiply(uint a) returns(uint d) { return a * 7; } }' 66 | } 67 | } 68 | ``` 69 | 编译器也可以通过[RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC)调用,因此 借助RPC/IPC,也可以在连接至geth的浏览器内置Dapp中通过[web3.js](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcompilesolidity)调用. 70 | 71 | 以下示例显示了如何通过JSON-RPC连接`geth`以使用编译器。 72 | ``` 73 | ./geth --datadir ~/eth/ --loglevel 6 --logtostderr=true --rpc --rpcport 8100 --rpccorsdomain '*' --mine console 2>> ~/eth/eth.log 74 | curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"],"id":1}' http://127.0.0.1:8100 75 | ``` 76 | 77 | 一个源文件的编译器输出将为您提供表示单个合约的合约对象。`eth.compile.solidity`的实际返回值是合约名称 - 合约对象对的映射。由于我们的合同名称是`test`,`eth.compile.solidity(source).test`将为您提供包含以下字段的`test`合约的合约对象: 78 | 79 | * `code`: 编译过的EVM码 80 | * `info`: 编译输出的元信息的其他部分 81 | * `source`: 源码 82 | * `language`: 合约语言 (Solidity, Serpent, LLL) 83 | * `languageVersion`: 合约语言版本 84 | * `compilerVersion`: 编译器版本 85 | * `abiDefinition`: [应用二进制接口定义](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) 86 | * `userDoc`: [NatSpec用户文档](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-%20Format) 87 | * `developerDoc`: [NatSpec开发者文档](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format) 88 | 89 | 编译器输出的直接结构(`code`和`info`)反映了两个非常不同的部署路径。编译的EVM代码通过合同创建事务发送到块链,而其余的(info)将理想地像云一样分散分布,作为可公开验证的元数据补充块上的代码。 90 | 91 | 如果您的源包含多个合约,则输出将包含每个合约的条目,可以使用合约名称作为属性名称检索相应的合约信息对象。您可以通过检查最新的GlobalRegistrar代码来尝试这一点: 92 | 93 | `contracts = eth.compile.solidity(globalRegistrarSrc)` 94 | -------------------------------------------------------------------------------- /5.5生成和部署合约.md: -------------------------------------------------------------------------------- 1 | ## 生成和部署合约 2 | 既然你既有一个已经解锁的帐户也有一些资金,你可以通过将一个事务[发送](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethsendtransaction)到空的地址,使用evm代码作为数据来创建一个智能合约。是不是很简单? 3 | ``` 4 | primaryAddress = eth.accounts[0] 5 | MyContract = eth.contract(abi); 6 | contact = MyContract.new(arg1, arg2, ...,{from: primaryAddress, data: evmCode}) 7 | ``` 8 | 所有二进制数据以十六进制形式进行序列化。十六进制字符串始终具有十六进制前缀0x。 9 | 10 | 注意,这`arg1`, `arg2`, ...是合约构造函数的参数,假使它可以接受任何数据。 11 | 12 | 另请注意,此步骤要求您支付执行费用。一旦您的交易进入一个区块,您帐户(作为发件人填写在`from`区域)上的余额将根据VM的gas规则减少。稍后再说。一段时间后,您的交易应该显示在一个块中,确认其所带来的状态是一致的。你的合约现在部署到blockchain上。 13 | 14 | 执行相同操作的异步方式如下所示: 15 | ``` 16 | MyContract.new([arg1, arg2, ...,]{from: primaryAccount, data: evmCode}, function(err, contract) { 17 | if (!err && contract.address) 18 | console.log(contract.address); 19 | }); 20 | ``` 21 | -------------------------------------------------------------------------------- /5.6Gas和交易花费.md: -------------------------------------------------------------------------------- 1 | ## Gas和交易花费 2 | 那么你是如何付钱的呢?私底下,交易规定了gas限额和gasprice,两者都可以直接在交易对象中指定。 3 | gas限额是为了保护您免受错误代码的运行而导致您的资金耗尽。`gasPrice`与`gas`表示你愿意支付执行事务的Wei的最高金额。你指定的`gasPrice`是矿工用来对交易进行排序以包含在块链中。一个单位gas的Wei的价格也就是VM的运营价格。 4 | 5 | 运行合约所产生的gas开支,将被您账户中的ether以您在交易中用`gasPrice`指定好的价格购买。如果您没有ether来满足完整运行代码的所有gas需求,则处理中止,所有中间状态更改将回滚到事务前的快照。执行停止点的gas已经被使用了,所以你的账户的余额将减少。交易对象字段`gas`和`gasPrice`上的这些参数可以调整。 6 | 该`value`字段与普通帐户之间的ether转移交易中的用法相同。换句话说,任何两个帐户之间,普通账户(即外部控制)或合约,都可以转移资金。如果您的合约资金用光,你会看到资金不足的提示。 7 | 8 | 对于测试和使用合约,您可以使用测试网络或[设置](https://github.com/ethereum/go-ethereum/wiki/Setting-up-private-network-or-local-cluster)与所有其他节点隔离的专用节点(或集群)。如果你要挖矿,你可以确保你的交易将被包含在下一个块中。您可以通过以下方式查看待处理的交易: 9 | 10 | ``` 11 | eth.getBlock("pending", true).transactions 12 | ``` 13 | 14 | 您可以通过数字或其哈希来检索块: 15 | ``` 16 | genesis = eth.getBlock(0) 17 | eth.getBlock(genesis.hash).hash == genesis.hash 18 | true 19 | ``` 20 | 使用`eth.blockNumber`来获得当前blockchain高度,也可以使用“latest”这个神奇参数访问当前头(最新块) 21 | ``` 22 | currentHeight = eth.blockNumber() 23 | eth.getBlock("latest").hash == eth.getBlock(eth.blockNumber).hash 24 | true 25 | ``` 26 | -------------------------------------------------------------------------------- /5.7与合约交互.md: -------------------------------------------------------------------------------- 1 | [eth.contract](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcontract)可用于定义符合其[ABI定义](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI)中所述的合约接口的合约类。 2 | ``` 3 | var Multiply7 = eth.contract(contract.info.abiDefinition); 4 | var myMultiply7 = Multiply7.at(address); 5 | ``` 6 | 7 | 现在,所有在abi中指定的函数调用都可以在合约实例中使用。您只需调用合同上的实例和chain上的那些方法,例如:`sendTransaction(3, {from: address})`或`call(3)`。两者之间的区别是`call`在您的计算机上本地执行“dry run”,而`sendTransaction`实际上会将您的交易提交到blockchain中,其执行结果将最终成为全球共识的一部分。 8 | 换句话说,如果您只对返回值感兴趣,请使用`call`,如果您只关心合约状态的“副作用”,使用`sendTransaction`。 9 | 10 | 在上面的例子中,没有副作用,因此`sendTransaction`只会消耗gas并增加宇宙的熵。所有“有用的”功能都使用`call`暴露出来: 11 | ``` 12 | myMultiply7.multiply.call(6) 13 | 42 14 | ``` 15 | 现在假设这个合约不是你的,你想要文档或看源代码。通过提供合同信息包并将其注册到块链中实现了此目的。该`admin`API为选择注册的任何合同提供了方便的方法来获取此包。要了解其工作原理,请阅读有关[Contract Metadata](https://github.com/ethereum/wiki/wiki/Contract-metadata)或阅读本文档的合约信息部署部分。 16 | ``` 17 | // get the contract info for contract address to do manual verification 18 | var info = admin.getContractInfo(address) // lookup, fetch, decode 19 | var source = info.source; 20 | var abiDef = info.abiDefinition 21 | ``` 22 | -------------------------------------------------------------------------------- /5.8合约信息(元数据).md: -------------------------------------------------------------------------------- 1 | ## 合约信息(元数据) 2 | 在上一节中,我们解释了如何在blockchain上创建合同。现在我们讨论编译器输出的其他部分,合约元数据或合约信息。这个想法是这样的 3 | * 合同信息被上传到可通过`url`公开访问的位置 4 | * 任何人都可以找到只知道合同的地址的`url` 5 | 6 | 这些要求通过使用2步blockchain注册机制非常简单地实现。第一步是在一个叫做`HashReg`的合约中注册一个带有内容哈希的合约代码(哈希)。第二步是在`UrlHint`合约中注册一个含有内容哈希的URL 。这些[简单的注册合约](https://github.com/ethereum/go-ethereum/blob/develop/common/registrar/contracts.go)将成为frontier提议的一部分。 7 | 8 | 所以如果你是一个认真的合约创建者,步骤如下: 9 | 1. 将合约本身部署到blockchain 10 | 2. 获取合约信息json文件。 11 | 3. 将合约信息json文件部署到您选择的任何URL 12 | 4. Register codehash - >content hash - > url 13 | 14 | JS API可以通过提供帮助来简化此过程。调用[admin.register](https://ethereum.gitbooks.io/frontier-guide/content/contract_info.html)从合约中提取信息,在给定文件中写出其json序列化,计算文件的内容哈希值,最后将该内容哈希值注册到合同的代码散列。将该文件部署到任何url后,您可以使用[admin.registerUrl](https://ethereum.gitbooks.io/frontier-guide/content/contract_info.html)在blockchain上注册带有内容哈希的URL。(请注意,如果使用固定内容寻址模型作为文档存储,则不再需要url提示。) 15 | ``` 16 | source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }" 17 | // compile with solc 18 | contract = eth.compile.solidity(source).test 19 | // create contract object 20 | var MyContract = eth.contract(contract.info.abiDefinition) 21 | // extracts info from contract, save the json serialisation in the given file, 22 | contenthash = admin.saveInfo(contract.info, "~/dapps/shared/contracts/test/info.json") 23 | // send off the contract to the blockchain 24 | MyContract.new({from: primaryAccount, data: contract.code}, function(error, contract){ 25 | if(!error && contract.address) { 26 | // calculates the content hash and registers it with the code hash in `HashReg` 27 | // it uses address to send the transaction. 28 | // returns the content hash that we use to register a url 29 | admin.register(primaryAccount, contract.address, contenthash) 30 | // here you deploy ~/dapps/shared/contracts/test/info.json to a url 31 | admin.registerUrl(primaryAccount, hash, url) 32 | } 33 | }); 34 | ``` 35 | -------------------------------------------------------------------------------- /5.9NatSpec.md: -------------------------------------------------------------------------------- 1 | ## NatSpec 2 | 本节将进一步阐述您可以通过NatSpec协议构建的合约和交易来做什么。Solidity实现doxigen风格智能注释,然后可以用它来生成代码的各种外观元文档。一种这样的用例是生成用于事务确认的客户端可以提示用户的自定义消息 3 | 4 | 所以我们现在通过一个智能注释来扩展`multiply7`合约,此评注释指定一个自定义确认消息(通知)。 5 | ``` 6 | contract test { 7 | /// @notice Will multiply `a` by 7. 8 | function multiply(uint a) returns(uint d) { 9 | return a * 7; 10 | } 11 | } 12 | ``` 13 | 该注释具有在反引号之间的表达式,当向用户呈现交易确认消息时需要评估它。引用了调用方法参数的变量根据用户(或用户的dapp)发送的实际交易数据进行实例化。在geth中,支持确认通知的NatSpec已全面实施。NatSpec依赖于abi定义以及userDoc组件来生成正确的确认信息。因此,为了达成这一目的,合约需要按照上述方式注册其合约信息。 14 | 15 | 让我们看看一个完整的例子。作为一个非常认真的智能合同开发商,您首先创建合同并按照上述推荐步骤进行部署: 16 | ``` 17 | source = "contract test { 18 | /// @notice Will multiply `a` by 7. 19 | function multiply(uint a) returns(uint d) { 20 | return a * 7; 21 | } 22 | }" 23 | contract = eth.compile.solidity(source).test 24 | MyContract = eth.contract(contract.info.abiDefinition) 25 | contenthash = admin.saveInfo(contract.info, "~/dapps/shared/contracts/test/info.json") 26 | MyContract.new({from: primary, data: contract.code}, function(error, contract){ 27 | if(!error && contract.address) { 28 | admin.register(primary, contract.address, contenthash) 29 | // put it up on your favourite oldworld site: 30 | admin.registerUrl(contentHash, "http://dapphub.com/test/info.json") 31 | } 32 | }); 33 | ``` 34 | 请注意,如果我们使用像群集这样的内容寻址存储系统,则第二步是不必要的,因为contenthash是(确定性地转换为)内容本身的唯一地址。 35 | 为了轻松地使用例子,只需简单地使用文件url方案(不完全是云,但会显示它如何工作)而不需要部署。 36 | ``` 37 | admin.registerUrl(contentHash, "file:///home/nirname/dapps/shared/contracts/test/info.json") 38 | ``` 39 | 现在你已经作为开发者完成了,所以切换下角色,假装你是一个发送一个交易到`multiply7`合约的用户。 40 | 41 | 您需要使用该`--natspec`标志启动客户端,以启用智能确认和contractInfo提取。您还可以在控制台上使用`admin.startNatSpec()`和`admin.stopNatSpec()`来设置它。 42 | 43 | 在控制台输入: 44 | ``` 45 | // obtain the abi definition for your contract 46 | var info = admin.getContractInfo(address) 47 | var abiDef = info.abiDefinition 48 | // instantiate a contract for transactions 49 | var Multiply7 = eth.contract(abiDef); 50 | var myMultiply7 = Multiply7.at(address); 51 | ``` 52 | 53 | 现在尝试发送一个真实的交易: 54 | ``` 55 | > myMultiply7.multiply.sendTransaction(6, {from: eth.accounts[0]}) 56 | NatSpec: Will multiply 6 by 7. 57 | Confirm? [y/n] y 58 | > 59 | ``` 60 | 当这个交易被包含在一个块中,幸运的矿工的计算机上的某个地方,6将被乘以7,结果被忽略。任务完成。 61 | 62 | 如果交易没有接收,我们可以通过下面的命令看到: 63 | ``` 64 | eth.pendingTransactions 65 | ``` 66 | 67 | 这将累积发送的所有事务,即使是被拒绝的事务,和未包括在当前的开采块(trans state)中的事务。后者可以通过以下方式表示: 68 | ``` 69 | eth.getBlock("pending", true).transactions() 70 | ``` 71 | 72 | 如果您确定被拒绝的交易的位置,则可以使用修改的gas限额和天gas价格(两个可选参数)重新发送: 73 | ``` 74 | tx = eth.pendingTransactions[1] 75 | eth.resend(tx, newGasPrice, newGasLimit) 76 | ``` 77 | -------------------------------------------------------------------------------- /5合约与交易.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | 3 | Ethereum是一个平台,旨在让人们轻松地使用blockchain技术编写分散式应用程序(Đapps)。分散应用程序是一种为其用户提供特定目的的应用程序,它具有重要的特性就是本身不依赖于现有的任何一方。Đapp不是作为销售的前端或者为特定方提供服务,而是一个交互应用的不同人员和组织走到一起的工具,且无需任何集中的中介。 4 | 5 | 通常在集中提供商的领域,例如过滤,身份管理,托管和争议解决,必要的“中介”功能由网络直接处理,或者让任何人参与进来,使用类似内部令牌系统和声誉系统的工具,以确保用户获得高质量的服务。Đapps的早期例子包括用于文件共享的BitTorrent和货币的BitCoin。Ethereum实现了 6 | BitTorrent和Bitcoin所使用的基本开发内容,并将其推广到一起,以便开发人员可以将这些技术用于任何目的。 7 | 8 | 可以将Ethereum blockchain描述为具有内置编程语言的blockchain,或作为基于共识的全局执行的虚拟机。实际处理内部状态和计算的协议部分被称为Ethereum虚拟机(EVM)。从实际的角度来看,EVM可以被认为是一个大型的分散式计算机,其中包含数百万个被称为“帐户”的对象,它们具有维护内部数据库,执行代码和交互的能力。 9 | 10 | 帐户有两种类型: 11 | * **外部帐户(EOAs)**:由私钥控制的帐户,如果您拥有与EOA关联的私钥,则可以发送ether和消息。 12 | * **合同**:具有自己的代码并由代码控制的帐户。 13 | 默认情况下,Ethereum执行环境是无生命的; 没有任何事情发生,每个帐户的状态保持不变。然而,任何用户都可以通过从外部拥有的帐户发送一个交易来触发一个动作,从而使Ethereum运转起来。如果交易的目的地是另一个EOA,那么交易可能会转移一些ether,但是其他方式的话什么都不做。然而,如果目的地是合同,那么合同又会激活并自动运行其代码。 14 | 15 | 代码能够读/写自己的内部存储(将32字节的密钥映射到32字节的值的数据库),读取接收到的消息的存储,并发送消息到其他合同,依次触发它们执行。一旦执行停止,由合同停止所发送的消息触发的所有子执行停止(这一切都以确定性和同步顺序发生,即子呼叫在父调用进一步完成之前完成),执行环境再次停止,直到被下一次交易唤醒。 16 | 17 | 合同通常有四个目的: 18 | 1. 维护一个代表对其他合同或外部世界有用的数据存储; 一个例子是模拟货币的合同,另一个是在特定组织中记录会员资格的合同。 19 | 2. 作为一种外部拥有的帐户,具有更复杂的访问策略; 这被称为“转发合同”,通常仅在满足某些条件时才简单地将传入消息重新发送到某个所需目的地; 例如,转发合同的时候,在重发之前等待,直到给定的三个私钥中的两个前已经确认了特定的消息(即,multisig)。更复杂的转发合同根据发送的消息的性质有不同的条件; 此功能的最简单的用例是通过一些更复杂的访问过程来覆盖的撤销限制。 20 | 3. 管理多个用户之间持续的合同或关系。这方面的例子包括一项财务合同,一些特定的介质的托管或某种保险。一方也可以有开放的合同,让任何其他方随时参与; 还有一个合同例子就是,自动向提交有效解决方案的人提供一些奖励,或证明它提供了一些计算资源。 21 | 4. 为其他合同提供职能; 作为软件库。 22 | 23 | 合同通过称为“calling”或“sending messages”的活动彼此交互。“message”是一个对象,它包含一定数量ether(Ethereum中使用的特殊内部货币,主要用于支付交易费用),一个任意大小的数据字节数组,发件人和收件人的地址。当合同收到一条消息时,可以选择返回一些数据,然后该消息的原始发件人可以立即使用。这样,发送消息就像调用函数一样。 24 | 25 | 因为合同可以发挥不同的作用,我们期望合同将相互交流。例如,考虑一个情况,Alice和Bob用100个GavCoin作为赌注,赌约是旧金山的温度在明年的任何时候都不会超过35ºC。但是,爱丽丝非常有安全意识,因为她的主要帐户使用的转发合同只能通过三个私钥中的两个的密钥发送消息。鲍勃对于量子加密技术是很偏执的,所以他使用一个转发合同,此合同只传递传统ECDSA和[Lamport signature](https://en.wikipedia.org/wiki/Lamport_signature)一起签名的消息(但是由于他是古板的人,他更喜欢使用基于SHA256的Lamport signature版本,Ethereum不直接支持)。 26 | 27 | 赌约合同本身需要从一些合同中获取关于旧金山天气的数据,并且在实际将GavCoin发送给Alice或Bob时候同GavCoin合约交流(或者更确切地说是Alice或Bob的转发合同)。因此,我们展示帐户之间的关系如下图: 28 | ![账户关系图](https://raw.githubusercontent.com/ethereumbuilders/GitBook/master/en/vitalik-diagrams/contract_relationship.png) 29 | 30 | 当鲍勃想完成赌注时,会发生以下步骤: 31 | 1. 发送一个交易,触发从Bob的EOA到Bob的转发合同的消息。 32 | 2. Bob的转发合同将消息的哈希和Lamport签名发送到作为Lamport签名验证库的合同。 33 | 3. Lamport签名验证库看到Bob想要一个基于SHA256的Lamport sig,所以根据需要多次调用SHA256库来验证签名。 34 | 4. 一旦Lamport签名验证库返回1,表示签名已经被验证,它会向表示下注的合同发送一条消息。 35 | 5. 下注的合同检查提供旧金山温度的合同,以查看温度是多少。 36 | 6. 下注合同看到,对消息的响应表明,温度高于35ºC,因此它向GavCoin合约发送消息,将GavCoin从其账户移动到Bob的转发合同。 37 | 38 | 请注意,GavCoin全部被“存储”作为GavCoin合同数据库中的条目; 在步骤6的上下文中,“account”这个词简单地意味着在GavCoin合约存储中有一个数据输入,其中有一个关键的赌注合同的地址和一个价值的余额。收到此消息后,GavCoin合约将此值减少一定数量,并增加与Bob转发合同地址相对应的条目中的值。我们可以在下图中看到这些步骤: 39 | 40 | ![步骤](https://raw.githubusercontent.com/ethereumbuilders/GitBook/master/en/vitalik-diagrams/contract_relationship2.png?1) 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-ethereum 2 | Ethereum Frontier Guide中文版,原地址为:https://ethereum.gitbooks.io/frontier-guide/content/ 3 | 本翻译只包括了第一章到第五章的内容,对于初学者来说,这个应该是最关心的内容了。 4 | 5 | ## 背景 6 | 最近我司在研究blockchain,看是否可以与现有业务结合产生新的火花,看了一些资料,以太坊是着重研究的对象。打算走truffle + go-ethereum路线,所以翻译Ethereum Frontier Guide,这个持续时间可能比较长,不过我应该会坚持下去,假如你同样有兴趣,可以Fork或者PR 7 | 8 | ## 推荐 9 | 推荐几个链接,我在研究过程中收藏的,由于花很多功夫在研读官方文档了,其他资料的搜集并不是很多。 10 | * [汪晓明的博客](http://wangxiaoming.com/) 11 | * [巴比特电子书](http://book.8btc.com/e_book) 12 | * [不是假网站](http://me.tryblockchain.org/week20170404.html) 13 | * [区块链技术中文社区](https://www.bitshuo.com/) 14 | --------------------------------------------------------------------------------