Etheteum wallet 账本结构解析和源码分析

第一部分 看看geth客户端的整体结构
创建私链的时候已经指定所有的信息都放在private-geth目录下,现在是已经有过挖矿的目录。

当时我们把创世文件genesis.json放在该目录下了、

root@i-5tthrr8u:/home/ubuntu/private-geth# ll
total 16
drwxr-xr-x 3 root   root   4096 Jul  2 17:02 ./
drwxr-xr-x 6 ubuntu ubuntu 4096 Jul  4 14:07 ../
drwx------ 5 root   root   4096 Jul  2 17:41 data/
-rw-r--r-- 1 root   root    529 Jul  2 16:29 genesis.json

进入真正的存放数据的目录private-geth/data/00
geth中保存的是区块链的相关数据
keystore中保存的是该链条中的用户信息

root@i-5tthrr8u:/home/ubuntu/private-geth/data/00# ll
total 20
drwx------ 4 root root 4096 Jul  2 17:23 ./
drwx------ 5 root root 4096 Jul  2 17:41 ../
drwxr-xr-x 5 root root 4096 Jul  2 17:02 geth/
-rw------- 1 root root 1391 Jul  2 17:58 history
drwx------ 2 root root 4096 Jul  2 17:10 keystore/

之前我们这个节点已经创建了两个账户,现在我们可以看到keystore里面有两个账户信息的文件

root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/keystore# ll
total 16
drwx------ 2 root root 4096 Jul  2 17:10 ./
drwx------ 4 root root 4096 Jul  2 17:23 ../
-rw------- 1 root root  491 Jul  2 17:02 UTC--2017-07-02T09-02-56.470592674Z--28b769b3b9109afd1e9e50a9312c5a3bfae8a699
-rw------- 1 root root  491 Jul  2 17:10 UTC--2017-07-02T09-10-28.087401309Z--b4e2e2514eae3684157bf34a0cee2c07c431cf92

每个账户都由一对钥匙定义,一个私钥和一个公钥。 账户以地址为索引,地址由公钥衍生而来,取公钥的最后 20个字节。每对私钥 /地址都编码在一个钥匙文件里。钥匙文件是JSON文本文件,可以用任何文本编辑器打开和浏览。钥匙文件的关键部分,账户私钥,通常用你创建帐户时设置的密码进行加密。钥匙文件的文件名格式为UTC。账号列出时是按字母顺序排列,但是由于时间戳格式,实际上它是按创建顺序排列。如果把秘钥丢了钥匙文件可以在以太坊节点数据目录的keystore子目录下找到,接下来我们进入一个keystore目录文件看看他的信息:

root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/keystore# vim UTC--2017-07-02T09-02-56.470592674Z--28b769b3b9109afd1e9e50a9312c5a3bfae8a699 

{"address":"28b769b3b9109afd1e9e50a9312c5a3bfae8a699",
"crypto":{
"cipher":"aes-128-ctr",
"ciphertext":"89ce1513b4b5a325735891b559c361ce696bb2c173a7a1b290549e79dad8f847",
"cipherparams":{"iv":"982c86418fae2dd39e04d1e51528cffa"},
"kdf":"scrypt",
"kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"4227384ea0e3d15af1bac190f7e01d392543d0a5ca1ec931c1d340f87845f771"},
"mac":"46cffc6e4f57fa27b69e53dc4ae43a03ce1b93f24c132aa4655f53ddf215f112"},
"id":"e516b9d4-2161-4648-b3db-fc2ef1c3739c",
"version":3
}

警告:记住密码并”备份钥匙文件”。为了从账号发送交易,包括发送以太币,你必须同时有钥匙文件和密码。确保钥匙文件有个备份并牢记密码,尽可能安全地存储它们。这里没有逃亡路径,如果钥匙文件丢失或忘记密码,就会丢失所有的以太币。没有密码不可能进入账号,也没有忘记密码选项。所以一定不要忘记密码。

接下来进入geth可以看到chaindata,lightchaindata,nodes目录

root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth# ll
total 24
drwxr-xr-x 5 root root 4096 Jul  2 17:02 ./
drwx------ 4 root root 4096 Jul  2 17:23 ../
drwxr-xr-x 2 root root 4096 Jul  4 14:12 chaindata/
drwxr-xr-x 2 root root 4096 Jul  2 17:02 lightchaindata/
-rw-r--r-- 1 root root    0 Jul  2 17:02 LOCK
-rw------- 1 root root   64 Jul  2 17:02 nodekey
drwxr-xr-x 2 root root 4096 Jul  4 15:55 nodes/

进入nodes(我们这条私链有三个节点,所以这里有三个ldb文件)

root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth/nodes# ll
total 5316
drwxr-xr-x 2 root root    4096 Jul  4 15:55 ./
drwxr-xr-x 5 root root    4096 Jul  2 17:02 ../
-rw-r--r-- 1 root root  405250 Jul  4 15:57 000033.log
-rw-r--r-- 1 root root 2132979 Jul  4 15:55 000035.ldb
-rw-r--r-- 1 root root 2131238 Jul  4 15:55 000036.ldb
-rw-r--r-- 1 root root  739354 Jul  4 15:55 000037.ldb
-rw-r--r-- 1 root root      16 Jul  4 14:12 CURRENT
-rw-r--r-- 1 root root       0 Jul  2 17:02 LOCK
-rw-r--r-- 1 root root    8187 Jul  4 15:55 LOG
-rw-r--r-- 1 root root    4557 Jul  4 15:55 MANIFEST-000013

进入chaindata,区块链最后的本地存储都是以ldb文件的形势(但这里是不是应该每个区块一个ldb文件呢?)

root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth/chaindata# ll
total 52
drwxr-xr-x 2 root root  4096 Jul  5 09:51 ./
drwxr-xr-x 5 root root  4096 Jul  2 17:02 ../
-rw-r--r-- 1 root root  5288 Jul  2 17:56 000008.ldb
-rw-r--r-- 1 root root 11681 Jul  4 14:12 000009.ldb
-rw-r--r-- 1 root root  8921 Jul  4 14:13 000010.log
-rw-r--r-- 1 root root    16 Jul  4 14:12 CURRENT
-rw-r--r-- 1 root root     0 Jul  2 17:02 LOCK
-rw-r--r-- 1 root root  2807 Jul  4 14:12 LOG
-rw-r--r-- 1 root root   346 Jul  4 14:12 MANIFEST-000011

进入Lightchaindata

root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth/lightchaindata# ll
total 24
drwxr-xr-x 2 root root 4096 Jul  2 17:02 ./
drwxr-xr-x 5 root root 4096 Jul  2 17:02 ../
-rw-r--r-- 1 root root 1237 Jul  2 17:02 000001.log
-rw-r--r-- 1 root root   16 Jul  2 17:02 CURRENT
-rw-r--r-- 1 root root    0 Jul  2 17:02 LOCK
-rw-r--r-- 1 root root  358 Jul  2 17:02 LOG
-rw-r--r-- 1 root root   54 Jul  2 17:02 MANIFEST-000000

第二部分 看看源码的结构

1 Core/types/block.go
首先看到的是一个区块的结构

// Block represents an entire block in the Ethereum blockchain.

type Block struct {
    header       *Header
    uncles       []*Header
    transactions Transactions

    // caches    hashsize字段是cache之用,避免多次 hash/sign导致性能损失
    hash atomic.Value
    size atomic.Value

    // Td is used by package core to store the total difficulty
    // of the chain up to and including the block.挖矿难度
    td *big.Int

    // These fields are used by package eth to track
    // inter-peer block relay.
    ReceivedAt   time.Time
    ReceivedFrom interface{}
}
这是一个区块体的结构,区块体是动态的存储数据的,主要包含了交易列表和uncle列表
// Body is a simple (mutable, non-safe) data container for storing and moving
// a block's data contents (transactions and uncles) together.
type Body struct {
    Transactions []*Transaction
    Uncles       []*Header
}
区块头的结构体,里面的参数我们都很熟悉就不解释了
// Header represents a block header in the Ethereum blockchain.
type Header struct {
    ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
    UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
    Coinbase    common.Address `json:"miner"            gencodec:"required"`
    Root        common.Hash    `json:"stateRoot"        gencodec:"required"`
    TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"`
    ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"`
    Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
    Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
    Number      *big.Int       `json:"number"           gencodec:"required"`
    GasLimit    *big.Int       `json:"gasLimit"         gencodec:"required"`
    GasUsed     *big.Int       `json:"gasUsed"          gencodec:"required"`
    Time        *big.Int       `json:"timestamp"        gencodec:"required"`
    Extra       []byte         `json:"extraData"        gencodec:"required"`
    MixDigest   common.Hash    `json:"mixHash"          gencodec:"required"`
    Nonce       BlockNonce     `json:"nonce"            gencodec:"required"`
}

2 这是一个交易的结构体
Core/types/transaction.go

1ContractTransaction的区别在于:Recipient == nil ; 2. Transaction能以RLP算法进行Encode和Decode; 3. hash/size/from字段是cache之用,避免多次 hash/sign导致性能损失;
type Transaction struct {
    data txdata
    // caches
    hash atomic.Value
    size atomic.Value
    from atomic.Value
}

type txdata struct {
    AccountNonce uint64          `json:"nonce"    gencodec:"required"`
    Price        *big.Int        `json:"gasPrice" gencodec:"required"`
    GasLimit     *big.Int        `json:"gas"      gencodec:"required"`
    Recipient    *common.Address `json:"to"       rlp:"nil"` // nil means contract creation
    Amount       *big.Int        `json:"value"    gencodec:"required"`
    Payload      []byte          `json:"input"    gencodec:"required"`

    // Signature values 签名
    V *big.Int `json:"v" gencodec:"required"`
    R *big.Int `json:"r" gencodec:"required"`
    S *big.Int `json:"s" gencodec:"required"`

    // This is only used when marshaling to JSON.
    Hash *common.Hash `json:"hash" rlp:"-"`
}

3 Receiptroot我们刚刚在区块头有看到,那他具体包含的是什么呢?它是一个交易的结果,主要包括了poststate,交易所花费的gas,bloom和logs


// Receipt represents the results of a transaction.
type Receipt struct {
    // Consensus fields
    PostState         []byte   `json:"root"              gencodec:"required"`
    CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"`
    Bloom             Bloom    `json:"logsBloom"         gencodec:"required"`
    Logs              []*Log   `json:"logs"              gencodec:"required"`

    // Implementation fields (don't reorder!)
    TxHash          common.Hash    `json:"transactionHash" gencodec:"required"`
    ContractAddress common.Address `json:"contractAddress"`
    GasUsed         *big.Int       `json:"gasUsed" gencodec:"required"`
}

4 一个个交易被打包到区块上面,那区块又是怎么变成去快链的呢?
Core/blockchain.go

// BlockChain represents the canonical chain given a database with a genesis block. The Blockchain manages chain imports, reverts, chain reorganisations.
// Importing blocks in to the block chain happens according to the set of rules defined by the two stage Validator. (需要两个阶段的验证)Processing of blocks is done using the Processor which processes the included transaction.(第一阶段交易的验证) The validation of the state is done in the second part of the Validator.(第二阶段state的验证) Failing results in aborting of the import.
// The BlockChain also helps in returning blocks from **any** chain included in the database as well as blocks that represents the canonical chain. It's important to note that GetBlock can return any block and does not need to be included in the canonical one where as GetBlockByNumber always represents the canonical chain.


type BlockChain struct {
    config *params.ChainConfig // chain & network configuration

    hc           *HeaderChain
    chainDb      **ethdb**.Database 本地数据库
    eventMux     *event.TypeMux
    genesisBlock *types.Block

    mu      sync.RWMutex // global mutex for locking chain operations
    chainmu sync.RWMutex // blockchain insertion lock
    procmu  sync.RWMutex // block processor lock

    checkpoint       int          // checkpoint counts towards the new checkpoint
    currentBlock     *types.Block // Current head of the block chain
    currentFastBlock *types.Block // Current head of the fast-sync chain (may be above the block chain!)

    stateCache   *state.StateDB // State database to reuse between imports (contains state cache)
    bodyCache    *lru.Cache     // Cache for the most recent block bodies
    bodyRLPCache *lru.Cache     // Cache for the most recent block bodies in RLP encoded format
    blockCache   *lru.Cache     // Cache for the most recent entire blocks
    futureBlocks *lru.Cache     // future blocks are blocks added for later processing

    quit    chan struct{} // blockchain quit channel
    running int32         // running must be called atomically
    // procInterrupt must be atomically called
    procInterrupt int32          // interrupt signaler for block processing
    wg            sync.WaitGroup // chain processing wait group for shutting down

    engine    consensus.Engine
    processor Processor // block processor interface
    validator Validator // block and state validator interface
    vmConfig  vm.Config

    badBlocks *lru.Cache // Bad block cache
}

注意:1. BlockChain无结构化查询需求,仅Hash查询, Key/Value数据库最方便; 2. 低层用LevelDB存储,性能好

5 stateDB用来存储世界状态
Core/state/statedb.go

// StateDBs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve:
// * Contracts
// * Accounts
type StateDB struct {
    db            ethdb.Database //本地数据库
    trie          *trie.SecureTrie
    pastTries     []*trie.SecureTrie
    codeSizeCache *lru.Cache

    // This map holds 'live' objects, which will get modified while processing a state transition.
    stateObjects           map[common.Address]*stateObject
    stateObjectsDirty      map[common.Address]struct{}
    stateObjectsDestructed map[common.Address]struct{}

    // The refund counter, also used by state transitioning.
    refund *big.Int

    thash, bhash common.Hash
    txIndex      int
    logs         map[common.Hash][]*types.Log
    logSize      uint

    preimages map[common.Hash][]byte

    // Journal of state modifications. This is the backbone of
    // Snapshot and RevertToSnapshot.
    journal        journal
    validRevisions []revision
    nextRevisionId int

    lock sync.Mutex
}

注意:1. StateDB完整记录Transaction的执行情况; 2. StateDB的重点是StateObjects; 3. StateDB中的 stateObjects,Account的Address为 key,记录其Balance、nonce、code、codeHash ,以及tire中的 {string:Hash}等信息;

那我们接下来看看stateObject结构体
Core/state/state_object.go

// stateObject represents an Ethereum account which is being modified.
//
// The usage pattern is as follows:
// First you need to obtain a state object.
// Account values can be accessed and modified through the object.
// Finally, call CommitTrie to write the modified storage trie into a database.
type stateObject struct {
    address common.Address // Ethereum address of this account
    data    Account
    db      *StateDB

    // DB error.
    // State objects are used by the consensus core and VM which are
    // unable to deal with database-level errors. Any error that occurs
    // during a database read is memoized here and will eventually be returned
    // by StateDB.Commit.
    dbErr error

    // Write caches.
    trie *trie.SecureTrie // storage trie, which becomes non-nil on first access
    code Code             // contract bytecode, which gets set when code is loaded

    cachedStorage Storage // Storage entry cache to avoid duplicate reads
    dirtyStorage  Storage // Storage entries that need to be flushed to disk

    // Cache flags.
    // When an object is marked suicided it will be delete from the trie
    // during the "update" phase of the state transition.
    dirtyCode bool // true if the code was updated
    suicided  bool
    touched   bool
    deleted   bool
    onDirty   func(addr common.Address) // Callback method to mark a state object newly dirty
}

再看看state的一个接口,可以查看账户的余额,nonce,代码和storage

// ChainStateReader wraps access to the state trie of the canonical blockchain. Note that implementations of the interface may be unable to return state values for old blocks.
// In many cases, using CallContract can be preferable to reading raw contract storage.

type ChainStateReader interface {
    BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)
    StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error)
    CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
    NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error)
}

所有的结构凑明朗了,那具体的验证过程是怎么样的呢
Core/state_processor.go
Core/state_transition.go
Core/block_validator.go

StateProcessor 1. 调用StateTransition,验证(执行)Transaction; 2. 计算Gas、Recipt、Uncle Reward

// StateProcessor is a basic Processor, which takes care of transitioning
// state from one point to another.
//
// StateProcessor implements Processor.
type StateProcessor struct {
    config *params.ChainConfig // Chain configuration options
    bc     *BlockChain         // Canonical block chain
    engine consensus.Engine    // Consensus engine used for block rewards
}

StateTransition
1. 验证(执行)Transaction;
3. 扣除transaction.data.payload计算数据所需要消耗的gas;
4. 在vm中执行code(生成contract or 执行contract);vm执 行过程中,其gas会被自动消耗。如果gas不足,vm会自 选退出;
5. 将多余的gas退回到sender.balance中;
6. 将消耗的gas换成balance加到当前env.Coinbase()中;

/*
The State Transitioning Model

A state transition is a change made when a transaction is applied to the current world state
The state transitioning model does all all the necessary work to work out a valid new state root.

1) Nonce handling
2) Pre pay gas
3) Create a new state object if the recipient is \0*32
4) Value transfer
== If contract creation ==
  4a) Attempt to run transaction data
  4b) If valid, use result as code for the new state object
== end ==
5) Run Script section
6) Derive new state root
*/
type StateTransition struct {
    gp         *GasPool
    msg        Message
    gas        uint64
    gasPrice   *big.Int
    initialGas *big.Int
    value      *big.Int
    data       []byte
    state      vm.StateDB

    evm *vm.EVM
}

BlockValidator
1. 验证UsedGas
2. 验证Bloom
3. 验证receiptSha
4. 验证stateDB.IntermediateRoot

// BlockValidator is responsible for validating block headers, uncles and
// processed state.
//
// BlockValidator implements Validator.
type BlockValidator struct {
    config *params.ChainConfig // Chain configuration options
    bc     *BlockChain         // Canonical block chain
    engine consensus.Engine    // Consensus engine used for validating
}

 

可以注意到刚才的state和block都是写进db数据库的,那我们看一下leveldb数据库结构

type LDBDatabase struct {
    fn string      // filename for reporting
    db *leveldb.DB // LevelDB instance

    getTimer       gometrics.Timer // Timer for measuring the database get request counts and latencies
    putTimer       gometrics.Timer // Timer for measuring the database put request counts and latencies
    delTimer       gometrics.Timer // Timer for measuring the database delete request counts and latencies
    missMeter      gometrics.Meter // Meter for measuring the missed database get requests
    readMeter      gometrics.Meter // Meter for measuring the database get request data usage
    writeMeter     gometrics.Meter // Meter for measuring the database put request data usage
    compTimeMeter  gometrics.Meter // Meter for measuring the total time spent in database compaction
    compReadMeter  gometrics.Meter // Meter for measuring the data read during compaction
    compWriteMeter gometrics.Meter // Meter for measuring the data written during compaction

    quitLock sync.Mutex      // Mutex protecting the quit channel access
    quitChan chan chan error // Quit channel to stop the metrics collection before closing the database

    log log.Logger // Contextual logger tracking the database path
}
type Database interface {
    Put(key []byte, value []byte) error
    Get(key []byte) ([]byte, error)
    Delete(key []byte) error
    Close()
    NewBatch() Batch
}

 

原文:http://blog.csdn.net/ddffr/article/details/74389051

区块链技术与身份识别(认证)进行结合

在今天的世界,没有身份就无法拥有银行账户,无法获得社会福利,无法形式受教育的权利,更不谈参与政治生活。同样,一个区块链上如果用户只有拥有匿名的地址而无法证明自己的真实身份,那么其应用场景必然变得狭窄。

ShoCard是一个将实体身份证件的数据指纹保存在区块链上的服务。用户用手机扫描自己的身份证件,ShoCard应用会把证件信息加密后保存在用户本地,把数据指纹保存到区块链。区块链上的数据指纹受一个私钥控制,只有持有私钥的用户自己才有权修改,ShoCard亦无权修改。同时,为了防范用户盗用他人身份证件扫描上传,ShoCard还允许银行等机构对用户的身份进行背书,确保真实性。

OneName则提供了另一种身份服务。任何比特币的用户都可以把自己的比特币地址和自己的姓名、Twitter、Facebook等账号绑定起来。相当于为每个社交账户提供了一个公开的比特币地址和进行数字签名的能力。

一个叫Bitnation的项目,则更为激进。用户在其官网上通过区块链登记成为bitnation的“公民”,并获得Bitnation“世界公民身份证”。然后凭此身份,获得Bitnation自我认可的各种公民服务。

与此相比,爱沙尼亚政府推出的“电子公民”计划可谓真正的接地气。2014年10月,其宣布向全世界开放“电子公民”身份认证服务。任何人只需要在其政府官网填写简单的信息,并用信用卡缴纳50欧元的申请费即可成为爱沙尼亚的电子公民。电子公民可以(1)线上登记注册并管理一间基于欧盟商业法律体系的欧盟企业;(2)获得爱沙尼亚政府认许的数字签名、认证与加密文件的网络服务;(3)在线开立爱沙尼亚的数位银行帐户;(4)使用全球跨境支付服务。《区块链:从数字货币到信用社会》(中信出版社)

作者:blockchain
链接:https://www.zhihu.com/question/42877886/answer/119517918
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Solidity编程 一 之智能合约的介绍

写在前面:

最新在学习以太坊相关的东西,Solidity是基础,所以对 http://solidity.readthedocs.io/en/latest/installing-solidity.html 里的文章进行了翻译。争取这篇文档都能完成翻译。由于自己的英语水平有限,如果在翻译的过程中有什么错误的,请留言,非常感谢!

1. 一个智能合约的例子

   我们从一个基础的solidity例子开始。开始的时候,你可能看不懂每一行具体的意思,但是没关系,我们会在后续的讲解中介绍每一个细节

pragma solidity ^0.4.0;
 
contract SimpleStorage {
    uint storedData;
 
    function set(uint x) {
        storedData = x;
    }
 
    function get() constant returns (uint) {
        return storedData;
    }
}

第一行告诉该合约用的是0.4.0版本的solidity编写,并且这些代码具有向上兼容性。保证不会在不同solidity编译版本下编译会出现不同的行为。

  从Solidity角度来看,合约就是存在于以太坊区块链中的一个特定地址中的代码和数据集合。uint storedData 声明了一个类型为 uint(256位的无符号整型)的变量,变量名称为 storedData。你可以把它想象为数据库中的一个字段,该字段是可以被数据库中的方法进行查询,修改。在以太坊中,这个字段是属于一个合约字段。在这个例子中,该变量可以通过提供的get,set方法进行获取或是修改。Solidity中,访问一个变量是不需要通过this来引用的。

  这个合约很简单,只是允许以太坊上的任何人来存储一个数据到某个节点,同时把这个操作发布到以太坊中,当然,以太坊上的其他节点同样可以通过调用set方法来修改你已经存储好的值。虽然有被修改,但是对该值操作的任何历史记录都是保存在以太坊中的。不用担心你的存储记录或是修改记录会丢失。后面我们会将到如何对合约进行限制,只允许你一个人修改这个数据

2. 子货币例子

  下面的例子将实现一个简单的加密货币例子。无中生币不在是梦想,当然只有合约的创建人才有这个特权。此外,任何人只要有一个以太坊密钥对就可以进行货币交易,根本不需要注册用户名和密码。

pragma solidity ^0.4.0;
 
contract Coin {
 
    //public关键字可以让外部访问该变量
    address public minter;
    mapping (address => uint) public balances;
 
    //事件可以让轻客户端快速的响应变化
    event Sent(address from, address to, uint amount);
 
    // 构造方法
    function Coin() {
        minter = msg.sender;
    }
 
    function mint(address receiver, uint amount) {
        if (msg.sender != minter) return;
        balances[receiver] += amount;
    }
 
    function send(address receiver, uint amount) {
        if (balances[msg.sender] < amount) return;
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        Sent(msg.sender, receiver, amount);
    }
}

 

这个合约引入了一些新的概念,让我们一个个都过一遍。

  address public minter; 

   声明了一个public,类型为address的状态变量。Address类型是一个160位的值,不允许任何的算术操作。它适合于存储合约地址或是其他人的密钥对。Public关键字会自动产生用于外部访问该变量值的方法。如果不声明public,其他的合约是无法访问该变量的。自动产生的方法类似于:

   function minter() returns (address) { return minter; }

   当然如果你增加了一个和上面完全一样的方法是没有任何作用的,我们需要变量和产生的方法名完全一致。这块其实编译器会帮助我们完成,不需要我们自己动手编写,我们只要知道这个概念就可以。

  mapping (address => uint) public balances;

   还是创建了一个公有状态变量,这是一个比address更复杂的数据类型,类似java里的Map<address,uint>,它描述了一个地址和一个uinit数据类型的map关系。Mappings的关系可以看成是一个hash表,所有可能的key都对应了一个0的值。当然在map里不存在只有key值或是只有value值的情况。所以我们需要记住添加了一个什么样的map关系或是像这个例子一样,如何使用它。因为这是个public变量,所以系统会自动为它生成一个get方法,类似于:

   function balances(address _account) returns (uint) {

        return balances[_account];

    }

  通过上面的方法我们可以很容易的查询一个账号的余额。

  event Sent(address from, address to, uint amount);

   这一行创建了一个名为event 的事件。该事件会在该示例的最后一行被触发。用户或是server应用可以花很低的代价(后面会讲代价是什么)来监听事件的触发。一旦这个事件被触发了,监听者接收到三个参数:from, to,amount.也是说从哪个账号,到哪个账号,金额是多少。通过这三个参数可以很容易追踪到具体的交易。为了监听这个事件,我们需要使用如下代码:

1
2
3
4
5
6
7
8
9
10
Coin.Sent().watch({}, '', function(error, result) {
    if (!error) {
        console.log("Coin transfer: " + result.args.amount +
            " coins were sent from " + result.args.from +
            " to " + result.args.to + ".");
        console.log("Balances now:\n" +
            "Sender: " + Coin.balances.call(result.args.from) +
            "Receiver: " + Coin.balances.call(result.args.to));
    }
})

注意用户是如何调用系统自动生成的balances方法

   Coin方法是构造方法,是在合约产生的时候系统会调用,而且之后不允许被调用。Msg(以及tx和block)是一个全局变量,保存了可以被区块链访问的一些属性。它持久化了创建合约的节点的地址。 Msg.sender是值该方法调用者的地址。

最后,真正完成合约功能的,并且被其他用户调用的是 mint和send方法。如果mint是被不是创建该合约的账号调用,不会起任何作用。但是,send可以被任何账号(必须有以太币的账号)调用并发送以太币给另外一个账号。注意,如果你用合约发送以太币到另外一个账号,通过区块链浏览器查看是查看不到任何变化的,因为发送以太币的过程和金额的变化都被存储在了特殊的以太币合约里。而不是体现在账号上。通过使用事件,可以很容易的创建一个区块链浏览器,用来查看交易和账号余额。

3. 区块链基础

 

   对于编程者来说,区块链不是一个很难理解的概念。因为最难懂的那部分(包括挖矿,哈希,椭圆加密,p2p网络)都只是提供了一系列的特性和约束。一旦你知道了这些特性和约束,你不必去理解这些特性或是约束背后的实现原理。

  交易

     区块链是全局共享,交易数据库。这就意味着任何人只要参与到这个网络中就可以访问到这个数据库。如果你要修改数据库中的数据,你需要创建一个被其他所有在这个网络里的人所认可的交易。交易说明对数据的修改要么没有任何进行要么就完全完成,不会出现部分完成,部分未完成的情况。而且一旦交易完成,被记录在数据库中,谁也无法修改这个交易。

     举个例子,想象在一个电子货币里,用表列举出所有账号余额。当进行一个账号和另外一个账号进行交易,交易数据库要确保交易金额要从交易发送方减去,并且在交易接收方增加同样的交易金额。如果交易过程中出现了任何原因导致交易失败,交易发送方增加金额的行为失败,那接收方的金额也不应该发生变化。

     而且发送方都会对发起的交易进行签名加密。这直接地保证了数据库只能被指定的修改所修改。在电子货币的例子中,简单的检查能够确保只有持有这个账号的秘钥者才能对金额进行转移。

  区块

     在比特币术语中,一个比较难理解的是 “双花攻击”问题:当网络中的两笔交易想同时清空同一个账号的余额会发生什么?一个冲突?

     理论上,你不需要去关心这种情况。系统会为你选择一个交易,这些交易会绑定在一个叫做 “区块”里,然后这些交易被执行并且分发到所有参与的节点。如果两笔交易相互冲突,后面执行的交易会被拒绝,不会成为区块的一部分。

      每一个区块都会及时的用线性组织起来,这就是区块链的最初来源。每一个区块都在一个固定时间加入到区块链中,对于以太坊来说,间隔为17秒。作为“序列化选择机制”(被称做挖矿)的一部分,可能会发生区块反复回滚情况,但是这种情况只是出现在区块链的末端。越多的区块被加入到末端,回滚操作就会越少。所以你的交易可能被回滚或是从区块链上被删除,但是你只要等的时间越长,这种情况发生的就会越少。

4.  以太坊虚拟机

  概述

     以太坊虚拟机(EVM)是以太网上智能合约的运行环境。这不仅仅是个沙盒,更确实的是一个完全独立的环境,也就是说代码运行在EVM里是没有网络,文件系统或是其他进程的。智能合约甚至被限制访问其他的智能合约

  账号 

     在以太坊中有两种账号共享地址空间:外部账号和合约账号。外部账号是由公钥和私钥控制的(如人),合约账号是由账号存储的代码所控制。

外部账号的地址是由公钥决定的,而合约地址是在智能合约被创建的时候决定的(这个地址由创建者的地址和发送方发送过来的交易数字衍生而来,这个数字通常被叫做“nonce”)

    不管是否账号存有代码(合约账号存储了代码,而外部账号没有),对于EVM来说这两种账号是相等的。

每一个账号都有持久化存储一个key和value长度都为256位字的键值对,被称为“storage”

而且,在以太坊中,每个账号都有一个余额(确切的是用“Wei”来作为基本单位)  ,该余额可以被发送方发送过来带有以太币的交易所更改。

  交易 

   交易是一个账号和另外一个账号之间的信息交换。它包含了二进制数据(消费数据)和以太数据。如果目标账号包含了代码,这个代码一旦被执行,那么它的消费数据就会作为一个输入数据。如果目标账号是一个0账号(地址为0的账号),交易会生成一个新的合约。这个合约的地址不为0,但是是来源于发送方,之后这个账号的交易数据会被发送。这个合约消费会被编译为EVM的二进制代码,并执行。这次的执行会被作为这个合约的代码持久化。这就是说:为了创建一个合约,你不需要发送真正的代码到这个合约上,事实上是代码的返回作为合约代码。

  Gas

      以太坊上的每笔进行一笔交易都会被收取一定数量的Gas.这是为了限制交易的数量,同时对每一笔交易的进行支付额外费用。当EVM执行一个交易,交易发起方就会根据定义的规则消耗对应的Gas。

  交易的创造者定义了的Gas 价格。所以交易发起方每次需要支付 gas_price * gas 。如果有gas在执行后有剩余,会以同样的方法返回给交易发起方。

  如果gas在任何时候消耗完,out-of-gas 异常会被抛出,那当前的这边交易所执行的后的状态全部会被回滚到初始状态。

  存储,主存和栈

       每个账号都有持久化的内存空间叫做存储. 存储是一个key和value长度都为256位的key-value键值对。从一个合约里列举存储是不大可能的。读取存储里的内容是需要一定的代价的,修改storage里的内容代价则会更大。一个合约只能读取或是修改自己的存储内容。

  第二内存区域叫做主存。系统会为每个消息的调用分配一个新的,被清空的主存空间。主存是线性并且以字节粒度寻址。读的粒度为32字节(256位),写可以是1个字节(8位)或是32个字节(256字节)。当访问一个字(256位)内存时,主存会按照字的大小来扩展。主存扩展时候,消耗Gas也必须要支付,主存的开销会随着其增长而增大(指数增长)。

      EVM不是一个基于寄存器,而是基于栈的。所以所有的计算都是在栈中执行。最大的size为1024个元素,每个元素为256位的字。栈的访问限于顶端,按照如下方式:允许拷贝最上面的16个元素中的一个到栈顶或是栈顶和它下面的16个元素中的一个进行交换。所有其他操作会从栈中取出两个(有可能是1个,多个,取决于操作)元素,把操作结果在放回栈中。当然也有可能把栈中元素放入到存储或是主存中,但是不可能在没有移除上层元素的时候,随意访问下层元素。

  指令集

    为了避免错误的实现而导致的一致性问题,EVM的指令集保留最小集合。所有的指令操作都是基于256位的字。包含有常用的算术,位操作,逻辑操作和比较操作。条件跳转或是非条件跳转都是允许的。而且合约可以访问当前区块的相关属性比如编号和时间戳。

  消息调用

        合约可以通过消息调用来实现调用其他合约或是发送以太币到非合约账号。消息调用和交易类似,他们都有一个源,一个目标,数据负载,以太币,gas和返回的数据。事实上,每个交易都包含有一个顶层消息调用,这个顶层消息可以依次创建更多的消息调用。

       一个合约可以定义内部消息调用需要消耗多少gas,多少gas需要被保留。如果在内部消息调用中出现out-of-gas异常,合约会被通知,会在栈里用一个错误值来标记。这种情况只是这次调用的gas被消耗完。在Solidity,这种情况下调用合约会引起一个人为异常,这种异常会抛出栈的信息。

      上面提到,调用合约会被分配到一个新的,并且是清空的主存,并能访问调用的负载。调用负载时被称为calldata的一个独立区域。调用结束后,返回一个存储在调用主存空间里的数据。这个存储空间是被调用者预先分配好的。调用限制的深度为1024.对于更加复杂的操作,我们更倾向于使用循环而不是递归。

  代理调用/ 代码调用和库

    存在一种特殊的消息调用,叫做代理调用。除了目标地址的代码在调用方的上下文中被执行,而且msg.sender和msg.value不会改变他们的值,其他都和消息调用一样。这就意味着合约可以在运行时动态的加载其他地址的代码。存储,当前地址,余额都和调用合约有关系。只有代码是从被调用方中获取。这就使得我们可以在Solidity中使用库。比如为了实现复杂的数据结构,可重用的代码可以应用于合约存储中。

  日志

   我们可以把数据存储在一个特殊索引的数据结构中。这个结构映射到区块层面的各个地方。为了实现这个事件,在Solidity把这个特性称为日志。合约在被创建出来后是不可以访问日志数据的。但是他们可以从区块链外面有效的访问这些数据。因为日志的部分数据是存储在bloom filters上。我们可以用有效并且安全加密的方式来查询这些数据。即使不用下载整个区块链数据(轻客户端)也能找到这些日志

  创建

   合约可以通过特殊的指令来创建其他合约。这些创建调用指令和普通的消息调用唯一区别是:负载数据被执行,结果作为代码被存储,调用者在栈里收到了新合约的地址。

  自毁

    从区块链中移除代码的唯一方法是合约在它的地址上执行了selfdestruct操作。这个账号下剩余的以太币会发送给指定的目标,存储和代码从栈中删除。

作者: shaotine

出处: http://www.cnblogs.com/StephenWu/

区块链学堂(第四课):以太坊Geth基本命令

进入Geth 命令行模式

在上一篇文章中,我们说到,我们可以用下面命令,建立一个新的私有链

geth --datadir "./" --nodiscover console 2>>geth.log

进入命令行模式,其中参数

  • –datadir 代表文件夹地址,
  • –nodiscover 代表该链条不希望被其他节点发现,
  • console >> geth.log 代表将控制台输出到文件geth.log中去

当然从命令行模式退出,也很简单,只要打入exit, 即可退出

Geth命令行中的Eth.accounts

我们在命令行输入 eth.accounts 可以看到当前该区块链中共有几个账号,以及每个账号的公钥地址。

p1

这里就要说到以太坊的账户体系了,

在以太坊系统中,状态是由被称为“账户”(每个账户由一个20字节的地址)的对象和在两个账户之间转移价值和信息的状态转换构成的。以太坊的账户包含四个部分:

  • 随机数,用于确定每笔交易只能被处理一次的计数器
  • 账户目前的以太币余额
  • 账户的合约代码,如果有的话
  • 账户的存储(默认为空)

简单地说,每一个以太坊账户都有一对公钥和私钥组成。

  • 公钥我们可以理解为就是账户地址,任何其他账户都可以访问该地址
  • 私钥可以理解为一段加密过的密码,这一对公钥和私钥共同组成一个唯一标示的以太坊账户。

例如在上节我们建立的第一个以太坊账户 eth.accounts[0] 中,地址 0xbcf5b841303bc08026ce2d3b8f83498ffe42c12f 就是公钥,而对密码加密而成的,就是私钥。

如何新增账户

我们可以输入命令 personal.newAccount("123") 来新建一个账户,(注意123可以修改为任何别的密码)

p2

这个时候我们可以看到除了第一个账户0xbcf5b841303bc08026ce2d3b8f83498ffe42c12f之外,还新增了另一个账户 0xb8b12a801b610176935a15321f77b48dd5c0c448, 此时输入eth.accounts, 就可以很轻松的看到有两个账户的公钥地址。

如何获取账户的以太币余额

在上一章中我们说过,当以太坊的私链在挖矿时候,所挖到的以太币都会存入第一个以太坊账户中,即eth.accounts[0] 中,而eth.accounts[1]默认是不会有以太币的。这个时候我们可以用下面的命令来查看eth.accounts[0] 中的以太币余额。

eth.getBalance("0xbcf5b841303bc08026ce2d3b8f83498ffe42c12f")
eth.getBalance("0xb8b12a801b610176935a15321f77b48dd5c0c448")
  • 其中0xbcf5b841303bc08026ce2d3b8f83498ffe42c12f是第一个账户的地址,
  • 0xb8b12a801b610176935a15321f77b48dd5c0c448 是第二个账户的地址 结果如下: p11

从上我们可以看得很清楚,挖矿得来的以太币都进了第一个账户,同时每个账户的公钥是该账户的核心。通过公钥我么可以对该账户的以太币进行增删改查各种操作

如何在两个账户之间进行以太币转换

前面说过每个账户的公钥(地址)是一切以太坊账户操作的核心,但地址字符串太长,我们用acc0/acc1 分别代表accounts[0]和[1],另外设置要转移0.01个以太币

> acc0 = eth.accounts[0]
"0xbcf5b841303bc08026ce2d3b8f83498ffe42c12f"
> acc1 = eth.accounts[1]
"0xb8b12a801b610176935a15321f77b48dd5c0c448"
> amount = web3.toWei(0.01)
"10000000000000000"

这个时候我们可以使用eth.sendTransaction来将0.01个以太币从acc0转移到acc1中。

> eth.sendTransaction({from: acc0, to: acc1, value: amount})

结果如下:

这个是以太坊的一个保护机制,每隔一段时间账户就会自动锁定,这个时候任何以太币在账户之间的转换都会被拒绝,除非把该账户解锁.

这个时候我们就需要执行 personal.unlockAccount(acc0) 并输入密码来解锁acc0才可。

> personal.unlockAccount(acc0)
Unlock account 0xbcf5b841303bc08026ce2d3b8f83498ffe42c12f
Passphrase: 
true
>

这个时候我们重新执行命令eth.sendTransaction({from: acc0, to: acc1, value: amount}), 结果如下:

> eth.sendTransaction({from: acc0, to: acc1, value: amount})
"0xeea74dd5ff3f1287614d52ebb674edb93e8c5e51e4296835044d3d858d3d9f10"
> eth.getBalance(acc1)
10000000000000000
>

我们可以看到这个时候acc1有了数值10000000000000000, 而不再是之前的0了。但我们明明要给0.01ether币的,为何数值会如此大呢? 其实是对的,我们只要输入命令web3.fromWei(10000000000000000,"ether") 就可以知道了。

> web3.fromWei(10000000000000000,"ether")
"0.01"

为什么呢,这个就涉及到以太坊的基本单位了,我们下章讲解.

———————————————————————————-

Ether币的基本单位

Ether币最小的单位是Wei,也是命令行默认的单位, 然后每1000个进一个单位,依次是

  • kwei (1000 Wei)
  • mwei (1000 KWei)
  • gwei (1000 mwei)
  • szabo (1000 gwei)
  • finney (1000 szabo)
  • ether (1000 finney)

简单地说就是就是1 以太币 = 1000000000000000000 Wei (这就是上一站章中为何我们转移0.01个以太币,结果却显示很长的原因)

如何进行ether 和 Wei之间的转换

Ether–> Wei:web3.toWei

> web3.toWei(1)
"1000000000000000000"
> web3.toWei(1.3423423)
"1342342300000000000"
> web3.toWei(0.00034)
"340000000000000"
>

Wei –> Ether: web3.fromWei

> web3.fromWei(10000000000000000)
"0.01"
> web3.fromWei(1000000000000000000)
"1"
>

一个以太币各单位之间的转换工具

http://ether.fund/tool/converter

使用很简单,输入各种单位,就可以自动得到各种转换结果,例如输入0.01ether 可以得到多少Wei, 多少finney等。

p4

开始挖矿 & 停止挖矿

> miner.start() //开始挖矿
true
> miner.stop() //停止挖矿
true
>

部署合约

注意合约部署的时候,以太坊的私有链必须处在挖矿进行的状态,否则合约部署将不会生效

  • 我们在命令行中,首先unlock(eth.accounts[0]),因为部署合约需要消耗gas,也就是以太币。而之前说过由于保护机制,不解锁账户,是不会允许任何以太币流出的。
> personal.unlockAccount(acc0)
Unlock account 0xbcf5b841303bc08026ce2d3b8f83498ffe42c12f
Passphrase: 
true
>
  • 然后我们复制黏贴下面代码到geth 命令行中。
var a_demotypesContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"f","outputs":[{"name":"b","type":"uint256"}],"payable":false,"type":"function"}]);
var a_demotypes = a_demotypesContract.new(
   {
     from: web3.eth.accounts[0], 
     data: '0x6060604052341561000c57fe5b5b60ab8061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063b3de648b14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b600060006008830290508091505b509190505600a165627a7a7230582010decdc0b0a43b565814fe904eae2544665457d6353c7d906fc2c43c81c867e40029', 
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

结果如下图:

p5

等待片刻,会发现合约被部署到挖矿挖出来的区块中了, 按下回车代表成功

p6

此时输入合约部署的实例a_demotypes, 可以看到a_demotypes的详情。

> a_demotypes
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "f",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  address: "0x54ed7a5f5a63ddada3bfe83b3e632adabaa5fc2f",
  transactionHash: "0x69cde62bcd6458e14f40497f4840f422911d63f5dea2b3a9833e6810db64a1c9",
  allEvents: function(),
  f: function()
}
>

也可以调用a_demotypes的方法f, 输入任何数字,会返回8*n,如输入100,返回800,输入125,返回1000

> a_demotypes.f.call(100)
800
> a_demotypes.f.call(125)
1000
由此可见该合约在我们的私有链上部署成功!

迅雷,玩客币,撕逼戏,商业思路,技术科普看这一篇文章就够了

一.“迅雷”,“迅雷大数据”傻傻分不清楚?

迅雷就是美国上市的那个迅雷,曾经持股迅雷大数据28.77%的股权,但是并没有董事会席位。市场上称迅雷大数据是迅雷的子公司,是因为迅雷的数据的实际控制者於菲一直担任迅雷的高级副总裁,和迅雷创始人邹胜龙关系甚密代表了老创业团队的利益,与现任CEO陈磊代表的有战略方向上的矛盾。小米入住迅雷持股超过40%,看中的是迅雷的子业务星域CDN,这个业务归属于子公司网心科技,而原来网心科技的CEO陈磊现在是迅雷的CEO。本来嘛老团队大喊一声皮皮虾,我们走,去搞迅雷大数据赚钱去,和迅雷搞分布式CDN的分道扬镳,各玩各的也挺好,但是怎么玩着玩着就开始撕逼了呢?

二.因为迅雷要断迅雷大数据的财路。

这事儿要从玩客币说起。几年前迅雷搞赚钱宝,也挺火的,但是干炒一个分布式CDN没掀起多大风浪,今年的第三代设备改名玩客云开始发玩客币,一下子挠到了市场的敏感地带。被比特币挑起的欲望和因为禁止ICO带来的饥渴叠加在一起形成的干柴烈火一下子把迅雷的股票从四块多烧到了27。中概区块链第一股的金字名头意味着还有更大的想象空间,不过迅雷的团队还是一个居安思危的好团队,他们首先想到的是不是拿赚来的钱吃火锅,今天吃酸菜鱼火锅,明天吃牛又火锅。而是把儿子迅雷大数据拉过来声明断绝父子关系。

听着有点儿奇怪,但是道理很简单,因为迅雷大数据是个拿着老爸名头四处坑蒙拐骗的败家子。拿着免费从迅雷那里导来的流量做外汇交易,小额贷款之类的非法业务赚钱。迅雷自己做的这个玩客币本身就存在争议,再加上这么个挂着迅雷名头的子公司,到时候监管部门以人民的名义老子儿子的账一起算,真就比李刚还惨。

11月28日迅雷上午发布公告称,迅雷已正式撤销迅雷金融、迅雷易贷、迅雷小游戏、迅雷爱交易等业务的品牌和商标授权,并要求其全面停止对迅雷商标的任何使用。

对于迅雷大数据来说,这位老铁扎的可不是心是我的老命啊,反击是必然的,他们称迅雷是假区块链真ICO;效果是明显的,迅雷的股价从27到11。商场上你来我往本来也是正常,但是一上来就要鱼死网破的不多,毕竟迅雷完了迅雷大数据也一样没了流量和名头。只能说赚钱可能已经不是赚钱本身这么简单了,或许已经成为了某种信仰,那种同归于尽的架势真有点类似自杀式攻击,你断了我的财路就是亵渎了我的神啊。情急之下,文章标题竟然是《九评XXX》这是要跟苏联修正主义开战的战斗檄文,在今天的网络环境下有点儿敏感,也暴露了於菲姐姐的真实年龄。

三.小米摆平迅雷大数据

快进掉整个撕逼过程直接看撕逼的结果,小米联合创始人王川担任迅雷董事长,力挺陈磊,玩客币更名链克并联合打击玩客币交易网站,邹胜龙退位,迅雷大数据更名摸金狗继续摸金摸狗不再使用迅雷的名字。

为啥小米能迅速摆平呢?三个原因。

1.雷军系的实力摆在那里。

2.迅雷大数据的老团队靠的还是创始人邹胜龙,但是邹胜龙好歹有10%的迅雷股份,眼看它蒸蒸日上,谁会坐视它被同归于尽?

3.玩客币这个东西,监管部门没想一棍子打死。

12月12日新华网发文称迅雷采用实名制措施打击ICO和黄牛炒作。甭管效果如何,看上去是个乖孩子,可以说在近期没有了被取缔的风险。当然风险和收益是对等的,近期也就没有了玩客币疯炒的基本面。

那么,迅雷是怎么从PC时代的下载王者变成今天的区块链第一股的呢?来,请说出你的故事。

四.玩客币是有中心节点的区块链,正如迅雷当年是有中心节点做资源目录服务器的P2P

2005年,迅雷这个名字诞生,在那之前菊花还是一种植物,在那之前P2P下载还是在互联网公平共享的精神下的去中心分布式协议。之后的故事是迅雷作为一个垄断资源的中心节点,在以迅雷节点为中央的网络环境下,大家一边开心地下载小片片,一边卸载电驴等各色BT软件加入到迅雷这个有家长的大家庭,垫定了迅雷4万万用户的江湖地位。

有人骂360流氓,因为他说装谁就装谁,说卸谁就卸谁。

有人骂快播是流氓,因为他提供盗版下载。

迅雷集合了两大流氓的精髓。他提供盗版下载,他控制了下载要你做迅雷会员,然后想让谁下载快就让谁下载快,不想让谁下载快谁就没速度。

在这里我们不做道德判断,也不深入讨论技术原理,只是讲明了从控制了中心资源节点的P2P网络,到如今有中心的区块链账本并不突兀。

有了区块链才有的比特币,但是二者待遇相差悬殊,目前我们国家是禁止比特币的,而区块链成为中国人民银行数字货币研究所的主要研究对象。因为比特币是无政府的,而区块链则不等于没有中心,而是分为三种,无中心的公有链,有中心的联盟链和私有链。公有链没有中心所以也就无法封堵,这是比特币的魅力所在,按下葫芦浮起瓢,不怕任何央行的围堵,而有中心的联盟链就容易被擒贼先擒王,然后树倒猢狲散。看上去玩客云属于联盟链。关于比特币,区块链这里就不再科普了,您如果想懂早就懂了,如果不懂菠萝博士一篇文章也说不清楚。

总之经过一番撕逼,玩客币改名链克,区块链技术的应用还是很有底气的,同时区块链本身不会被禁,只要不要搞链克兑换人民币就行,只不过,人家外国的交易网站要交换,我努力了禁不掉你看我至少看上去还是很乖的不是吗?

如果迅雷搞游戏用链克买道具呢?长远看,只要有价值,交易所是必然要存在的。

五.玩客云的商业原理和未来发展

不谈情怀,就说钱。

16年3季度营收总额4730万美元,分会员,广告,云计算三大块。会员已经是昨日黄花,广告算是平稳,云计算增长,总的来说还亏损。自从有了玩客云,以上三个都不重要了。

第一笔钱:矿机

399一台的矿机预定量两千多万台,开放购买以后卖出去超过一千万还是没问题的。这台矿机=4核1.5CPU+1G内存+外壳,类比树莓派大概160元人民币的价格,实际总成本最多两百多,每台利润超过一百元,一千万台就是7亿美元收入,1.5亿净利润。四个字,咸鱼翻身。

矿机不同于手机,没那么多零件,不需要等待各种供应链上的其他部件,产能不会有问题,问题只有一个,是否有足够的矿工不断的加入进来。如果没有,那么这个收入就是不可持续的,为了有,迅雷不会希望玩客币没有炒作价值。

第二笔钱:云计算

如果是过去的迅雷,或许圈完第一笔钱就没有动作了,但是现在是雷军的迅雷。我猜雷军和迅雷的目标是云计算,只不过现在还差距很远。对比一下播控云4999的价格,也许你该明白了些什么。

看图说话,请在如下阿里云的产品列表中找出CDN

在整张大图上,跟迅雷和网心科技相关的只有CDN,而CDN在整个云计算收入中占比不高,大概有百分之十,在阿里的屠刀下纷纷降价,蓝汛,宿网之类收入连年下降股价跌到接近一块钱濒临退市。

更惨的是,CDN的市场中迅雷似乎也还没打出一片天,但它的分布式CDN概念挺有意思。传统的CDN是一些节点,分布在全国各地,上面缓存了中心服务上面的东西,用户在打开页面的时候,不用去遥远的中心服务器下载,而是去相对附近的服务器上下载。就好比快递网络,每次都是去快递站拿,要比每次都去卖家仓库里拿快多了。分布式CDN的概念就牛逼啦,直接把快递放在了小区每家每户,需要拿快递的时候直接去隔壁老王家就好了,速度当然是飞一样的感觉啦。

技术上来说,和过去的迅雷下载没啥区别,比如小米电视里面的电视剧,用了星域CDN,只要把内容给到网心科技,它会提前放到各个矿机提供的硬盘上,就像是当年有人上传了文件到迅雷的P2P下载平台,当有人打开小米电视看电视剧的时候,就相当于过去从迅雷的P2P网络中下载文件。

刚刚推出的保镖传输大文件的产品也是大同小异的原理。

所以长期来看,迅雷需要先证明分布式CDN的优势,再进一步打云计算市场,如果说阿里是用亚马逊的方式造公有云,那么迅雷就得用矿工的算力来打造分布式的公有云。这东西很多年前就有人提出来过,叫做网格计算,能不能成功,请参考一本畅销书名《少有人走过的路》(开玩笑的)。如果迅雷+金山一起搞呢?那雷军系会不会就不再是一个靠耍猴卖手机的团伙了?

第三笔钱:3亿个链克

迅雷留给自己3亿个链克,这些链克价值几何?取决于长期的稀缺性和短期的供应量。玩客币的发行机制第一年5.95亿个,第二年2.97亿个,第三年1.49亿个,第四年0.74亿个占总量的5%,第五年3%,第六年1%。三年以后,币值很定大涨。前提是刚才说的第二笔钱要有一个不错的表现。和挖比特币相比,如果挖链克的过程是为分布式云计算提供算力,那么这本身就有实用价值而不是只计算一个无用的hash。这时候手握3亿个链克的迅雷,几乎等于手握黄金的央行。

感谢你读到这里,这是我第一篇文章,欢迎关注菠萝博士的公众号,以后会更加认真的写,如果做不到,至少可以做到不发垃圾内容浪费您的宝贵阅读时间,接下来会写一套儿童python编程入门的教程,或许可以让小朋友和没学过编程的大人打开一扇窗,认识一个新的世界,渴望您能关注。

多说一句,最近玩客猴火了,提醒一下,玩客猴并不是一个区块链应用,而是一个普通的游戏,他和crypto最大的区别是玩客猴的数据是数据库中的,和普通的游戏没区别,而crypto中的每一个猫都是一个智能合约。

转自:菠萝博士