课程链接 https://www.coursera.org/learn/decentralized-apps-on-blockchain/home/week/2
为自己学习记的笔记,翻译可能存在问题,望谅解。
Truffle 开发
目录
Truffle IDETruffle Development: Truffle IDE (Part1)
Truffle IDE (Part 2) (Compile Demo)
Truffle IDE (Part 3) (Migration Demo)
测试驱动开发 Test-Driven Development
Test-Driven Development (Part 1) (Test Demo)
Test-Driven Development (Part 2) (Negative Test Demo)
Web Interface & TestingWeb Interface & Testing (Part 1) (Front-End Demo)
Web Interface & Testing (Part 2) (Metamask Demo)
Web Interface & Testing (Part 3) (Metamask Demo Con't)
Truffle IDE
Truffle Development: Truffle IDE (Part1)
我们准备开发端到端的去中心化应用程序。 Truffle是一站式IDE,可提供从初始应用程序模板到本地区块链的所有内容,以测试完整的Dapp。 与使用remix IDE测试智能合约的方法类似,我们将使用Truffle IDE环境组装Dapp的各种组件。
学习目标:
1)完成本模块后,您将可以使用Truffle IDE进行Dapp开发,
2)通过创建智能合约和端到端Dapp探索Dapp开发过程。
3)说明测试驱动的开发对智能合约尤其重要。
4)此外,您将能够通过本地区块链和Injected Web3环境Metamask在区块链服务器的前端进行交互。
学习目标:
1)您将能够提出Dapp问题定义,
2)概述解决问题的方法,
3)使用智能合约设计高级解决方案
4)识别Truffle IDE的组件。
我们选择讨论了Solidity文档的智能合约,voting.sol 或 ballot.sol 中指定的问题。 它代表了普遍的问题,即通过民主投票来选择获胜者或领导者。它代表了从产品评论到购买的各种场景,这些评论是基于收到的好评而购买的。 此外,还可以通过理事机构中有关预算的法律。 让我们从回顾选票Dapp开始。
我们的目标是设计和开发Dapp进行投票,该Dapp可以在许多项目中进行选择,例如一组提案或产品。 在我们的案例中,我们将选择四种不同水果的受欢迎程度。主席组织了投票。 选民通过其帐户地址进行标识。 这是要执行的逻辑或规则。 只有主席可以注册其他选民。 一个选民只能注册一次。 只有注册的选民才能投票。 选民只能投票一次。 没有 “write in” 的意思是选民只能对提出的项目投票。 主席的投票权重是普通选民的两倍。
为了仅专注于Dapp开发过程,我们将不处理投票的时间要素或阶段。 此时,我们将讨论设计过程的四个步骤。
1)我们将使用智能合约和实体来表示问题的主要逻辑。 我们将从数据和操作开始。
2)我们将添加修饰符和验证检查以确保解决了问题定义中指定的规则。
3)我们将设计一个测试智能合约,以确保满足所有规定的要求。 这就像单元测试。
4)成功完成单元测试后,我们将添加前端组件并测试完成的Dapp。 这就像集成测试。
将刚才讨论的一般设计过程应用到选票应用程序需要五个步骤。
1)我们将设计 ballot.sol
2)用一个修饰符 “onlyOwner” 举例,它指定有资格的人为主席。回想一下,在智能合约的设计中,您可以使用修饰符来表示全局规则。
3)我们将为所需的问题说明添加测试人员代码,然后运行测试以确保它们全部通过。
4)我们将添加用户界面组件。
5)我们将通过与接口交互来测试完整的应用程序。
记住,在编写代码之前进行设计
ballot smart contract
我们如何解决问题或将解决方案导入Truffle IDE?
Truffle是一个集成的开发环境或IDE,为Dapp开发提供了一系列功能,
truffle init:包括用于初始化Dapp的模板或基本目录结构的命令。
truffle compile 编译:智能合约编译。
truffle develop 开发:用于使用控制台进行测试的本地测试区块链,
truffle migrate 迁移:用于部署智能合约的迁移脚本,
truffle test 测试:一个测试环境,用于测试部署的合同。
接下来,我们需要安装几个软件包,包括 Node.js,它将作为 Dapp 前端的 web 服务器。Truffle 4.0.4 和 Metamask 3.14.1 Chrome插件。
你可能需要从Metamask IO中添加Metamask插件到你的Chrome浏览器中。它将链接到由truffle创建的区块链来管理帐户,充当应用程序前端和托管帐户的区块链节点之间的桥梁。
我们提供了一个Linux命令表来帮助您完成这个任务。
Truffle IDE (Part 2) (Compile Demo)
接下来,我们将创建一个Ballot1文件夹,因为我们将使用多个版本的选票。Truffle提供了一个具有所需结构的文件夹模板目录。要知道,在发出命令行中的命令之前,必须运行虚拟机并启动终端。
1)首先,为您的项目创建一个名为Ballot1的文件夹。
2)定位到工作文件夹,在这个文件夹中,通过 mkdir Ballot1 创建一个名为 Ballot1 的目录或文件夹。然后通过 cd ballot1导航到这个选票目录。一旦进入,就可以开始初始化项目了。您可以使用 truffle init 命令来实现这一点。
3)一旦执行了 truffle init,您将看到三个文件夹目录:contracts、migrations、test。contracts 目录 包含我们智能合约的可靠性源文件。Migrations 目录,Truffle使用一个迁移系统 migration system 来处理合约部署。test 目录 包含我们智能合约的 JavaScript 和稳定性测试。
这里有一个重要的智能合约 migration.sol 是为促进部署 facilitating deployment 的智能合约。
4) truffle.js。truffle 配置文件,它指定了区块链网络ID、IP和RPC端口。
如何使用 truffle IDE 编译智能合约
1)添加合约 ballot.sol 到合约目录;
2)将目录更改回 bollet 的根目录,并使用 truffle compile 进行编译。
****以下内容是视频截图,尚未实际操作,实际操作后补图。
1)先在命令行输入 truffle init
2)通过查看文件夹,可以看到 contracts,migration, test 以及一些 Script 文件。进入该 contract 文件夹,可以看到一个用 solidity 编写的智能合约 Migrations.sol ,它有助于我们编写的智能合约的迁移。
4)进入 migration 文件夹,可以看到一个 script 文件 1_initial_migrations.js ,它有助于 migration.sol 的部署。
1_initial_migrations.js
var Migrations = artifacts.require("Migrations");
module.exports = function(deployer) {
deployer.deploy(Migrations);
};
migration.sol
pragma solidity ^0.4.17;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
function Migrations() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
5)test 文件夹里目前什么都没有,我们可以在这里添加测试脚本。(后面内容有讲到)
以上是基本模板。
如何加入 Ballot.sol 呢?(仅进行视频描述,具体操作因人而异)
1)使用 pwd 命令显示当前所在工作目录的全路径。
2)将 CourseraDocs 中的 Ballot.sol 文件复制到 contracts文件夹中。进入 contracts 文件夹目录,可以看到已经复制成功。
3)回到根目录进行编译。使用 truffle compine 命令进行编译。它编译了两个 contract 文件夹中的智能合约。如果智能合约存在语法错误,会提示出来。它创建了一个新的文件夹,而这正是编译器生成的构建工件 build artifacts 的位置。
打开编译器:进入 contracts 文件夹,输入 gedit Ballot.sol & 并把它放在后台,这样在编译器打开时也可以做其他事情。
编译时提示有编译错误时可以进入编译器进行修改,但是最好的方式还是使用 Remix 进行编译。
Ballot.sol
pragma solidity ^0.4.17;
contract Ballot {
struct Voter {
uint weight;
bool voted;
uint8 vote;
// address delegate;
}
//modifer
modifier onlyOwner () {
require(msg.sender == chairperson);
_;
}
/* struct Proposal {
uint voteCount; // could add other data about proposal
} */
address public chairperson;
mapping(address => Voter) public voters;
uint[4] public proposals;
// Create a new ballot with 4 different proposals.
function Ballot() public {
chairperson = msg.sender;
voters[chairperson].weight = 2;
}
/// Give $(toVoter) the right to vote on this ballot.
/// May only be called by $(chairperson).
function register(address toVoter) public onlyOwner{
if(voters[toVoter].weight != 0) revert();
voters[toVoter].weight = 1;
voters[toVoter].voted = false;
}
/// Give a single vote to proposal $(toProposal).
function vote(uint8 toProposal) public {
Voter storage sender = voters[msg.sender];
if (sender.voted || toProposal >= 4 || sender.weight == 0) revert();
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal] += sender.weight;
}
function winningProposal() public constant returns (uint8 _winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < 4; prop++)
if (proposals[prop] > winningVoteCount) {
winningVoteCount = proposals[prop];
_winningProposal = prop;
}
}
}
配置 truffle 编译环境:
将ballot home中的空 truffle.js 文件直接替换为这里显示的文件。这将设置您接下来将部署的本地区块链的配置。 9545是Truffle提供的测试链的RPC端口。
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
networks: {
development: {
host: "localhost",
port: 9545,
network_id: "*" // Match any network id
}
}
};
使用Truffle部署本地区块链:
1)在一个新终端中,定位到 bollet 的 home 位置并部署 开发区块链 development blockchain。命令是 truffle develop。该命令将部署一个本地测试区块链,其中包含您将看到的10个帐户地址。
2)在将这些帐户链接到钱包 或 诸如MetaMask之类的界面(稍后我们将使用)时,它还将显示种子词 seed words。 将单词保存好,您也可以将保存的单词复制到文件中。
3)我们需要向migrations目录添加一个文件来部署smart contract。在 migrations 目录下创建文件 2_deploy_contracts.js ,在文件中添加如下内容:
var Ballot = artifacts.require("Ballot");
module.exports = function(deployer) {
deployer.deploy(Ballot);
};
Truffle IDE (Part 3) (Migration Demo)
在执行时,您将看到使用有效的合约名称将成功的 migrations 保存到网络。您还可以看到 message Saving 工件,这些是我们在课程2 中研究的编译过程生成的工件。
课程2 中已经成功编译了 ballot ,现在将其部署或迁移到测试链中。
(必须先部署测试链,然后才能在其上部署智能合约。)
****本文中所有图片为视频截图,尚未实际操作,实际操作后补图。
1)查看目录,有一个 truffle.js 文件,它是我们测试链的配置。可以看到目前它里面没有内容。
2)将Coursera Docs 中的 truffle.js 文件复制过来:
关于主机IP是什么以及主机将通过哪个端口号连接到Web应用程序以及网络ID本身,有一些详细信息。
3)部署这个测试链。先进入一个新的终端,进入有 truffle.js 的相同文件夹,输入命令 truffle develop
该操作为我部署一个测试链,有10个帐户,地址从帐户0到帐户9都可以看到,这些私钥的私钥也是256位。地址是160位,还显示了 seed words ,请保存好这些 seed words ,我们可能会在链接测试链时用到。
4)我们的链已经准备好了,打开之前的终端进行操作:
现在我们准备将我们的智能编译合约迁移或部署到这里。为了部署,我们还需要把这个文件 2_deploy_contracts 复制到 Migrations 文件夹中。
5)这是一个开发阶段,所以如果您对之前部署的智能合约版本不满意,我们可以覆盖之前的智能合约。一旦你部署了智能合约,你就不能改变它。在这里,我将重置之前可能部署的任何 ballot ,使用命令 truffle --reset,这将部署编译后的智能契约。
您可以看到它使用了我们刚才创建的网络开发。 然后,它部署用于基础迁移的初始迁移,然后部署我们编译的 ballot 合约。 并且还保存了稍后将在连接到工件时使用的工件。
您可以用Truffle控制台 console 做什么?
控制台为测试链上创建的帐户以及我们前面在模块1中讨论的管理API提供了命令行界面。
下面是一些用于在帐户之间传输数据的命令:
我们还通过将一个事务从一个帐户发送到另一个帐户并检查发送者的余额来测试 truffle 测试链。
总结:在这节课中,我们引入 ballot 问题来说明 Dapp 在 truffle 的开发过程。我们介绍了 truffle IDE 命令。我们还讨论了在Truffle IDE 上开发的 DApp 的目录结构。我们最后决定开发和部署一份智能合同。
阅读材料
TRUFFLE TUTORIAL INDEX
Linux command sheet
测试题
测试驱动开发 Test-Driven Development
Test-Driven Development (Part 1) (Test Demo)
测试是硬件开发的基本阶段。在产品发布之前测试是硬件设计的关键步骤。通常通过每周更新来提供软件系统上的错误修复。那么我们的智能合约(Dapps的核心逻辑)如何?
智能合约就像一个硬件芯片。一旦部署,它们将是最终版本,并且无法进行更新,除非内置了特殊规定或逃生舱口 escape hatches。测试对于智能合同来说是绝对必要的。
完成本课程后,您将能够详细解释测试驱动开发和测试脚本的重要性。
可以通过正面测试 positive tests 来进行 ballot 智能合约的测试,确保对于给定的有效输入,它可以按预期执行。
我们将测试 deploy,register,vote,winning proposal 的完整 ballot 周期。 并进行负面测试 negative test,确保它能够正确处理无效的输入和情况。
通常,测试人员用与要测试的主要应用程序相同的语言编写。您将以智能合约和Solidity语言编写测试器 tester 本身。Truffle Pet Shop 示例中对此有很好的说明。 但是,ballot 合约反复使用主席和选民的地址类型数据。当另一个智能合约用作测试器时,这会引起问题。 因此,我们将使用 Truffle 支持的替代语言(即JavaScript)编写测试。
Truffle 允许 JavaScript 和 Solidity 两种语言,我们将使用 JavaScript。 看一下 test.js,它有四个正面测试和两个负面测试。 如果我们可以使用编辑器打开 test.js,则可以继续进行。
到目前为止,我们已经使用 Truffle IDE 初始化了 Dapp 开发的模板,并将带有 ballot.sol 智能合约的模板添加到了 contracts 文件夹中。编译此智能合约并将其部署或迁移到 Truffle IDE 提供的测试链中。现在让我们测试它。为此,我们需要在 test 文件夹中提供一些测试脚本,如您所见,那里没有任何内容。我们将课程资源中的 test 脚本复制到 test 文件夹中。
让我们看看 test.js 包含什么。 我已经在 Atom 编辑器中将其打开。 我们设计的方式是先建立正测试用例,然后再建立几个负测试用例。稍后,我们可以添加任意数量的负面测试用例。
第一行写着我们需要 Ballot.sol 工件。然后创建此 Ballot 的 test instance,我们确保它被部署在第一个测试用例中。在第二个测试用例中,我们要确保良好的 user registration 正在进行中。我们正在注册三个账户,确保只有所有者可以注册。你可以看到这是有效的注册。第三个功能是 Valid voting 。第四个功能是 Validate winner。因此,前四个用例将完全测试管道 pipeline 或函数 deploy,register,vote,winning proposal 的进程。
接下来的两个测试用例是负测试用例,不是所有者试图注册一个帐户,一名未登记的选民正试图为这一进程投票。这里有两个测试用例,但是可能有更多。在后面的演示中会看到更多的测试用例。这将是您将来可能进行的应用程序测试的模板。你需要一些基本的JavaScript知识。
test.js
let Ballot = artifacts.require("./Ballot.sol");
let ballotInstance;
contract('Ballot Contract', function (accounts) {
//accounts[0] is the default account
//Positive Test 1
it("Contract deployment", function() {
return Ballot.deployed().then(function (instance) {
ballotInstance = instance;
assert(ballotInstance !== undefined, 'Ballot contract should be defined');
});
});
//Positive Test 2
it("Valid user registration", function() {
return ballotInstance.register(accounts[1], { from: accounts[0]}).then(function (result) {
assert.equal('0x01', result.receipt.status, 'Registration is valid');
return ballotInstance.register(accounts[2], { from: accounts[0]});
}).then(function (result) {
assert.equal('0x01', result.receipt.status, 'Registration is valid');
return ballotInstance.register(accounts[3], { from: accounts[0]});
}).then(function(result) {
assert.equal('0x01', result.receipt.status, 'Registration is valid');
});
});
//Positive Test 3
it("Valid voting", function() {
return ballotInstance.vote(2, {from: accounts[0]}).then(function (result) {
assert.equal('0x01', result.receipt.status, 'Voting is done');
return ballotInstance.vote(1, {from: accounts[1]});
}).then(function (result) {
assert.equal('0x01', result.receipt.status, 'Voting is done');
return ballotInstance.vote(1, {from: accounts[2]});
}).then(function (result) {
assert.equal('0x01', result.receipt.status, 'Voting is done');
return ballotInstance.vote(1, {from: accounts[3]});
}).then(function (result) {
assert.equal('0x01', result.receipt.status, 'Voting is done');
});
});
//Positive Test 4
it("Validate winner", function () {
return ballotInstance.winningProposal.call().then(function (result) {
assert.equal(1, result.toNumber(), 'Winner is validated with the expected winner');
});
});
//Negative Test 5
it("Should NOT accept unauthorized registration", function () {
return ballotInstance.register(accounts[6], { from: accounts[1]})
.then(function (result) {
/* If the user had handled the above mentioned failure case in solidity,
then this block will not be executed.
Truffle would directly throw the revert error which will be catched
*/
throw("Condition not implemented in Smart Contract");
}).catch(function (e) {
/* If the error is custom thrown then the condition was not checked and hence fail the test case
else pass the test case
*/
if(e === "Condition not implemented in Smart Contract") {
assert(false);
} else {
assert(true);
}
})
});
//Negative Test 6
it("Should NOT accept unregistered user vote", function () {
return ballotInstance.vote(1, {from: accounts[7]})
.then(function (result) {
throw("Condition not implemented in Smart Contract");
}).catch(function (e) {
if(e === "Condition not implemented in Smart Contract") {
assert(false);
} else {
assert(true);
}
})
});
});
回到基本目录,命令是 truffle test 。它编译了它,所以我们要对它进行双重测试。
您可以通过测试用例看到它。 有四个有效的测试用例,我们提供了很好的输入,并且确实进行了检查。 接下来的两个是错误的输入,您的 Solidity 智能合约确实将这些捕获为错误的输入,并且没有执行该操作。我们通过了六个测试。我们将在以后的投票演示中添加更多测试。
Test-Driven Development (Part 2) (Negative Test Demo)
现在在 contracts 文件夹中编辑 Ballot.sol。 从注册功能中删除 onlyOwner 。 保存 Ballot.sol。 您可以使用 gedit 编辑器或您熟悉的任何其他编辑器(例如atom)。导航回到基本目录,然后发出命令 truffle compile, truffle migrate, --reset, truffle test. 在这种情况下,重置 reset 非常重要,因为我们将覆盖智能合约的先前版本,而重置将解决该问题。 然后继续测试,truffle test。您会注意到其中一个负测试案例失败了。
第二次负面测试。 编辑 Ballot.sol,voter 函数。 删除(voter.weight == 0)和它前面的逗号,以便它不会检查未注册的选民。 这是一个错误。 保存。 浏览回到基本目录并再次重复该过程,进行 truffle compile, truffle migrate, --reset, truffle test ,您将看到另一个负测试用例失败。
现在回到Ballot.sol,对其进行编辑,添加已删除的项目。 在将 onlyOwner 添加到 register 函数的标题行中,并将 weight == 0 添加到 voter 函数之后,将其保存,执行 truffle 步骤以确保一切正常。 导航回基本目录, truffle compile, truffle migrate, --reset, truffle test 。 您应该看到所有测试都通过了。
现在让我们检查负面测试。 有两个负面测试。 一,由 owner 注册。 只有所有者可以注册。 第二个是仅注册帐户可以投票的帐户。 现在,我们将仅测试其中的一个,当我们拥有完整的层时,稍后将测试第二个。 对于第一个,我将进入合同文件夹并编辑gedit 我的 Ballot.sol 并转到 register 函数。 在 register 函数中,这里指定了一个修饰符 onlyOwner,只有所有者可以注册 ,我将删除它。可以正确编译,但其实是存在这个错误。测试时,正面测试通过,因为过程是正确的。但是,当涉及到负面测试时,由于我们没有指定 onlyOwner,并且该条件是由我们的负测试用例检查的,它会给我们一个错误。
到目前为止,您应该非常熟悉开发DApp的步骤。即使您不是 JavaScript 专家,也可以使用我们提供的 test.js 作为编写测试的模型。
阅读材料
Ethereum Pet Shop Dapp
Testing of Smart Contracts in the Blockchain world
Smart Contracts and Truffle 101. Part 4 - Testing Functions and Errors
测试题
Web Interface & Testing
Web Interface & Testing (Part 1) (Front-End Demo)
在本课程中,我们将向DApp添加Web界面。我们创建了一个预先填写的 ballot 应用程序。完成这节课后,你可以列出 Ballot.sol 的基本代码为链接到用户界面所做的更改,并将用户界面前端集成到选票智能合约和区块链后端。
解压 Ballot2.zip 这可能是任何DApp项目所需的基本结构。请注意,文件和目录比以前概述的要多。
我们知道,contracts 文件夹有智能合约,migration 文件夹内是迁移脚本,test 文件夹内是 test 脚本,build 包含由编译过程生成的JSON构件,源文件夹包含web资产,如JavaScript、CSS和索引HTML。Node module文件夹中有 Node.js 模块。JSON文件和JavaScript是配置文件。
现在,导航到提供 web 资产的源目录。 源 Java 的目录中有一个名为 app.js 的文件。 这实例化了Web客户端与区块链节点进行通信所需的对象。 我们需要公开通过应用程序的 web3 提供程序对象创建的区块链帐户。
简单地说,web3 init代码就是这样做的。它展示了如何创建web3对象并将其链接到我们应用的测试链。
其次,我们需要告诉web3在哪里可以找到智能合约工件。 app.js 的 Init Contract 方法可以做到这一点。 然后,您必须添加方法来处理对智能合约的调用,并将值从智能合约返回到Web界面。
app.js
App = {
web3Provider: null,
contracts: {},
names: new Array(),
url: 'http://127.0.0.1:9545',
chairPerson:null,
currentAccount:null,
init: function() {
$.getJSON('../proposals.json', function(data) {
var proposalsRow = $('#proposalsRow');
var proposalTemplate = $('#proposalTemplate');
for (i = 0; i < data.length; i ++) {
proposalTemplate.find('.panel-title').text(data[i].name);
proposalTemplate.find('img').attr('src', data[i].picture);
proposalTemplate.find('.btn-vote').attr('data-id', data[i].id);
proposalsRow.append(proposalTemplate.html());
App.names.push(data[i].name);
}
});
return App.initWeb3();
},
initWeb3: function() {
// Is there is an injected web3 instance?
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider;
} else {
// If no injected web3 instance is detected, fallback to the TestRPC
App.web3Provider = new Web3.providers.HttpProvider(App.url);
}
web3 = new Web3(App.web3Provider);
App.populateAddress();
return App.initContract();
},
initContract: function() {
$.getJSON('Ballot.json', function(data) {
// Get the necessary contract artifact file and instantiate it with truffle-contract
var voteArtifact = data;
App.contracts.vote = TruffleContract(voteArtifact);
// Set the provider for our contract
App.contracts.vote.setProvider(App.web3Provider);
App.getChairperson();
return App.bindEvents();
});
},
bindEvents: function() {
$(document).on('click', '.btn-vote', App.handleVote);
$(document).on('click', '#win-count', App.handleWinner);
$(document).on('click', '#register', function(){ var ad = $('#enter_address').val(); App.handleRegister(ad); });
},
populateAddress : function(){
new Web3(new Web3.providers.HttpProvider(App.url)).eth.getAccounts((err, accounts) => {
jQuery.each(accounts,function(i){
if(web3.eth.coinbase != accounts[i]){
var optionElement = '<option value="'+accounts[i]+'">'+accounts[i]+'</option';
jQuery('#enter_address').append(optionElement);
}
});
});
},
getChairperson : function(){
App.contracts.vote.deployed().then(function(instance) {
return instance.chairperson();
}).then(function(result) {
App.chairPerson = result.toString();
App.currentAccount = web3.eth.coinbase;
if(App.chairPerson != App.currentAccount){
jQuery('#address_div').css('display','none');
jQuery('#register_div').css('display','none');
}else{
jQuery('#address_div').css('display','block');
jQuery('#register_div').css('display','block');
}
})
},
handleRegister: function(addr){
var voteInstance;
App.contracts.vote.deployed().then(function(instance) {
voteInstance = instance;
return voteInstance.register(addr);
}).then( function(result){
if(result.receipt.status == '0x01')
alert(addr + " is registered successfully")
else
alert(addr + " account registeration failed due to revert")
}).catch( function(err){
alert(addr + " account registeration failed")
})
},
handleVote: function(event) {
event.preventDefault();
var proposalId = parseInt($(event.target).data('id'));
var voteInstance;
web3.eth.getAccounts(function(error, accounts) {
var account = accounts[0];
App.contracts.vote.deployed().then(function(instance) {
voteInstance = instance;
return voteInstance.vote(proposalId, {from: account});
}).then(function(result){
if(result.receipt.status == '0x01')
alert(account + " voting done successfully")
else
alert(account + " voting not done successfully due to revert")
}).catch(function(err){
alert(account + " voting failed")
});
});
},
handleWinner : function() {
var voteInstance;
App.contracts.vote.deployed().then(function(instance) {
voteInstance = instance;
return voteInstance.winningProposal();
}).then(function(res){
alert(App.names[res] + " is the winner ! :)");
}).catch(function(err){
console.log(err.message);
})
}
};
$(function() {
$(window).load(function() {
App.init();
console.log('starting app.js');
});
});
这里指出几个函数,我正在创建一个应用程序对象,该对象将初始化web3对象,该对象将成为您前端应用程序中所有区块链报告的接收者。 然后它将传递给在区块链中打开的基础RPC端点。
init contract ,即一个 web3 对象。 该 init contract 将指出智能合约所需的所有工件,在本例中为 Ballot.json。
handleRegister,处理智能合约的注册函数。
handleVote,这是你的智能合约的投票功能的粘合剂。
handleWinner,这是一个处理您的智能合约中 winningProposals 的功能。
所以,你可以用这个作为模板来开发你的前端。这是一个重要的文件,它是你的智能合约和前端之间的管道。
回到基础目录并进行编译。
测试,truffle test,可以看到所有的十个测试用例都通过了,您可以查看 test.js 以了解更多关于测试用例的信息。
我将部署一个更新的版本。
最后,运行 lite server。这是用于我们将要 npm run 的网页,运行开发服务器,run dev,这将打开一个Web端点,该端点将显示我们的所有Web资产。
导航回到有效的基本目录。 为了创建Web界面,最少需要一个index.html文件。 我们还添加了其他网络资产,例如我们要投票的项目的图像,资金和CSS样式文件。 目前,您至少有两个选择。 如果您具有前端开发技能,则可以创建自己的前端,也可以只使用源目录中提供的Web资产。
检查所有文件。
Web Interface & Testing (Part 2) (Metamask Demo)
重新打开测试链 test chain,我们已经完成了以下内容。现在启动Chrome浏览器。去 metamask.io 获取 Chrome 的 metamask 扩展。
MetaMask是我们的区块链服务器和网络之间的桥梁。 我们已将其添加为Chrome扩展程序。 这是我们探索的首选方法。 MetaMask就像一个数字钱包,提供连接到基础区块链节点,管理账户,猜测交易要点和余额的功能。 MetaMask还提供了一个简单的界面来对交易进行签名并传输执行交易所需的猜测点 guess points。
MetaMask安装迅速。 它很容易使用。 如果它与您的区块链服务器不同步,请立即删除并再次添加它。 现在,让我们看看如何将MetaMask链接到区块链服务器。 在truffle IDE中,由 truffle develop 命令部署的测试链的默认端口为9545。帐户地址通过此端口公开。 现在,让我们链接MetaMask来为我们的DApp管理它。
**接下来的内容关于MetaMask的设置操作并不复杂,可以参考其他博文。
Web Interface & Testing (Part 3) (Metamask Demo Con't)
我已经准备好了前端节点,并且MetaMask拥有了所有帐户,并且我在这里创建了五个帐户,我将通过注册一些帐户开始。进行注册,注册成功。这些是您在app.js中形成的支持功能,这些功能将这些功能带到了网络上。用同样的方式注册其他账户。从帐户1开始投票。帐户1的投票权重是2,我们将它投票给香蕉。除了所有者账户1以外,其他四个账户都投票给苹果。您会看到猜测点和其他内容确实得到了反映,并负责MetaMask管理。尝试用账户2注册新账户,失败。尝试用尚未注册的账户进行投票,也是失败的。最终的获胜者是苹果 。这是一个完整的 Dapp 演示。
阅读材料
Smart Contracts and Truffle 101. Part 3 - Simple functions and tests
Ethereum dApp tutorial - Front end. Part 1
测试题