以太坊实战:一个简单转账的实现

概述

本文讲解了如何通过以太坊私链来进行转账。在学习以太坊实战之前,请先根据我写的这篇文章搭建好以太坊的私有链。

基于以太坊私链模拟转账

进入控制台

先按上一篇文章开启一个节点,可以先通过命令:miner.stop()停止挖矿。再按以下命令进入控制台:

geth --datadir "./db" attach ipc:./db/geth.ipc
  • 1

1. 新建账户

为了完成转账,我们首先需要创建两个账号,如下:

  • 创建第一个账户
> personal.newAccount("hover")
"0x8663aca6d67330041e3218de54e3123bcea9e866"
> 

personal.newAccount函数的参数是账户的密码。执行成功后会返回账户的公钥,生成的账户文件在keystore文件夹下,此时工作目录geth的目录结构如下:

├── db
│   ├── geth
│   │   ├── chaindata
│   │   │   ├── 000002.ldb
│   │   │   ├── 000003.log
│   │   │   ├── CURRENT
│   │   │   ├── CURRENT.bak
│   │   │   ├── LOCK
│   │   │   ├── LOG
│   │   │   └── MANIFEST-000004
│   │   ├── lightchaindata
│   │   │   ├── 000001.log
│   │   │   ├── CURRENT
│   │   │   ├── LOCK
│   │   │   ├── LOG
│   │   │   └── MANIFEST-000000
│   │   ├── LOCK
│   │   ├── nodekey
│   │   ├── nodes
│   │   │   ├── 000001.log
│   │   │   ├── CURRENT
│   │   │   ├── LOCK
│   │   │   ├── LOG
│   │   │   └── MANIFEST-000000
│   │   └── transactions.rlp
│   ├── geth.ipc
│   └── keystore
│       └── UTC--2018-08-26T03-56-48.638581930Z--8663aca6d67330041e3218de54e3123bcea9e866

其中账户信息在keystore文件夹下。

  • 创建第2个账户
> personal.newAccount("123")
"0x96c275557213349816d57c4b482378eef1552150"

再看一下keystore下的目录结构:

 └── keystore
│       ├── UTC--2018-08-26T03-56-48.638581930Z--8663aca6d67330041e3218de54e3123bcea9e866
│       └── UTC--2018-08-26T04-02-57.501956829Z--96c275557213349816d57c4b482378eef1552150

查看一下目前账户的情况:

> eth.accounts
["0x8663aca6d67330041e3218de54e3123bcea9e866", "0x96c275557213349816d57c4b482378eef1552150"]

好了,现在我们已经有了两个账户。

2.查看余额

要完成转账首先需要有余额,我先查看一下目前账户的余额情况:

> balance = web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
0
> balance = web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
0

eth.accounts[index]会按传入的索引返回已有的账户。eth.getBalance(address)会返回账户的余额,余额以wei为单位。传入的参数是账户的公钥,web3.fromWei单位转换,在这个例子中是将wei转换成ether。

通过以上例子我们看到两个账户的余额都是0,我们需要通过挖矿开获取以太币,下面来挖矿。

3.挖矿

在挖矿前,我们需要设置挖矿的奖励地址。
* 设置奖励地址

> miner.setEtherbase(eth.accounts[0])
true
  • 查看是否设置成功
> eth.coinbase
"0x8663aca6d67330041e3218de54e3123bcea9e866"
> eth.accounts
["0x8663aca6d67330041e3218de54e3123bcea9e866", "0x96c275557213349816d57c4b482378eef1552150"]

eth.coinbase是设置的奖励地址。从以上命令,我们可以看到,已经设置成功了。

  • 开始挖矿
miner.start(1)
  •  

start的参数是线程数,我这里设置的是1。此时要是attach到某个节点上,那么可以该节点上看到对应的输出:

...
INFO [08-26|15:36:22.591] Successfully sealed new block            number=31 hash=14416f…bf92ab elapsed=550.351ms
INFO [08-26|15:36:22.592] ? block reached canonical chain          number=26 hash=034961…db0845
INFO [08-26|15:36:22.592] ? mined potential block                  number=31 hash=14416f…bf92ab
INFO [08-26|15:36:22.592] Commit new mining work                   number=32 uncles=0 txs=0 gas=0 fees=0 elapsed=116.351µs
INFO [08-26|15:36:23.070] Successfully sealed new block            number=32 hash=ea42ae…74e5a4 elapsed=477.569ms
INFO [08-26|15:36:23.070] ? block reached canonical chain          number=27 hash=9d3a02…ea355a
INFO [08-26|15:36:23.070] ? mined potential block                  number=32 hash=ea42ae…74e5a4
INFO [08-26|15:36:23.070] Commit new mining work                   number=33 uncles=0 txs=0 gas=0 fees=0 elapsed=119.824µs
INFO [08-26|15:36:23.548] Successfully sealed new block            number=33 hash=7e4983…8995f0 elapsed=478.359ms
INFO [08-26|15:36:23.549] ? block reached canonical chain          number=28 hash=8d8380…e21886
INFO [08-26|15:36:23.549] ? mined potential block  
...
  • 停止挖矿
miner.stop()
  • 查看现在的余额
> balance = web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
415

4.解锁账号

在开始转账之前需要先解锁账号,否则会报错。

> personal.unlockAccount(eth.accounts[0], "123", 900)
true

其中的第1个参数是:账户。第2个参数是:密码。第3个参数是:解锁的持续时间。

5. 交易:转账

>eth.sendTransaction({from: eth.accounts[0], to : eth.accounts[1], value: web3.toWei(10, "ether")})
"0x4edf43809d4c5603a2dfd8496ddb056d1725ffd80e8afaf95132447f19168548"

当交易发送到区块链后,会返回一个交易的hash,此时的交易正在矿工的交易池中等待被打包。可以查看交易池中等待被打包的交易:

> txpool.status
{
  pending: 1,
  queued: 0
}

有一个交易被pending,还没有被处理。可以查看pending交易的详情:

> txpool.inspect.pending
{
  0xDaE3d4234AD88421Bb4Dd5033143d25d8760DbfA: {
    0: "0xFF50D7746384D7e5a8769EA5501B2f894C241a14: 10000000000000000000 wei + 90000 gas × 18000000000 wei"
  }
}

6. 再次挖矿,让交易被处理

要让交易被处理,就必须要挖矿。我们启动挖矿,然后等待挖到一个区块链后就停止:

> miner.start(1); admin.sleepBlocks(1); miner.stop();
true

再查看未被处理的交易情况:

> txpool.inspect.pending
{}

可以看到,已经没有未被处理的交易。

查看余额:确认交易成功

> balance = web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
410
> balance = web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
10

可以看到,交易已经成功,成功的把10个以太币从账户0,转移到账户1。但这里的数量好像不对?
415-10=405,应该剩下405,怎么剩下410呢?
原因是,这里的coinbase账号是account[0],而每个区块生成的(挖矿成功)的奖励是5,所以这里是405+5=410。
这说明,我们的转账成功了。

查看交易详情

把刚才发起交易时返回的交易hash值传入eth.getTransaction函数,即可得到交易的详情。

> eth.getTransaction("0x4edf43809d4c5603a2dfd8496ddb056d1725ffd80e8afaf95132447f19168548")
{
  blockHash: "0xf232c92c07bbb7c1728567515ade844190b975d481c1e9017d0fa7dc445d76c4",
  blockNumber: 108,
  from: "0xdae3d4234ad88421bb4dd5033143d25d8760dbfa",
  gas: 90000,
  gasPrice: 18000000000,
  hash: "0x4edf43809d4c5603a2dfd8496ddb056d1725ffd80e8afaf95132447f19168548",
  input: "0x",
  nonce: 0,
  r: "0x10dec63e3844284d2568e68c233ddbdfedf287783e8db03749e38da632acf109",
  s: "0x53ff6bc3821140a1711d98e26a4d3ca161af341605543f3ee8377a28032b70d7",
  to: "0xff50d7746384d7e5a8769ea5501b2f894c241a14",
  transactionIndex: 0,
  v: "0x4c",
  value: 10000000000000000000
}

查看区块详情

从交易的详情中可以得到区块号,通过eth.getBlock函数,可以获取到某个区块号的区块的详细信息。

> eth.getBlock(108)
{
  difficulty: 131834,
  extraData: "0xd98301080e846765746888676f312e31302e318664617277696e",
  gasLimit: 3864853197,
  gasUsed: 21000,
  hash: "0xf232c92c07bbb7c1728567515ade844190b975d481c1e9017d0fa7dc445d76c4",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0xdae3d4234ad88421bb4dd5033143d25d8760dbfa",
  mixHash: "0x7e58396f67a9e4cc706d29c54544492caa6b44b04b4cb7e9e62e6f6642333be3",
  nonce: "0x6bde023f861f3089",
  number: 108,
  parentHash: "0x43832c74e796c1b22675419ddfc66374e2aa283174d864fb6fd5179ef4419a01",
  receiptsRoot: "0xb1e76317cdac9eed95b9e30439dc4020f130f2b5d66b8c31d07906a0aef096a7",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 652,
  stateRoot: "0x30866579a619eaa4e0894d99e4fbbc1f1877f8ff9182e528b71ee02921ac766b",
  timestamp: 1535269782,
  totalDifficulty: 14391713,
  transactions: ["0x4edf43809d4c5603a2dfd8496ddb056d1725ffd80e8afaf95132447f19168548"],
  transactionsRoot: "0x7adf91188514ae548ca69b6b25c8e66c757340009630c39a8d4af60c0aecaf13",
  uncles: []
}

获取创世块的信息

> eth.getBlock(0)
{
  difficulty: 1,
  extraData: "0x777573686f756865",
  gasLimit: 4294967295,
  gasUsed: 0,
  hash: "0x8c0faf797027b7e1f0fc0528ef73ec4b7cf2c9d19f358c19a0d770506737fa8e",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x0000000000000000000000000000000000000000",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000001",
  number: 0,
  parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 513,
  stateRoot: "0x614bf1b5ff99d2d78f80b391f520819f5cc0d873c822944a9497b9aabae5b159",
  timestamp: 0,
  totalDifficulty: 1,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

总结

本文描述了如何通过以太坊私有链的命令来发起交易,查看区块信息,执行交易等操作。并结合一个转账的场景进行了模拟使用。

上一篇:【以太坊价格】以太坊设置新的ATH,为什么ETH可以继续上涨至1,950美元


下一篇:VUE学习笔记