智能合约,加密国家智能合约,空投智能合约,ERC20代币智能合约编写

智能合约,加密国家智能合约

CryptoCountries.io Countries

加密国家智能合约编写

空投智能合约编写

ERC20代币智能合约编写

 

可以找我,全网最低

备注:智能合约

 

SBTC币,sbtc币 官网,超级比特币,超级比特币(SBTC)是什么?

搜索搜到:

http://www.superbtc.org/

http://supersmartbitcoin.com/index_ch.html

 

超级比特币(SBTC)是什么?
历时3年的比特币扩容之争严重阻滞了比特币的发展进程,与此同时,更是遭遇以太坊, Zcash等创新币种的强势围攻,丧失了巨量的市场份额。扼腕叹息之余,遂开始集聚社区内众多极客, 决意为比特币的继续前进注入新的动力,此举更是荣获多位颇具威望的社区领袖的赞许与支持。 我们将在498888的高度进行分叉试验,为比特币加入新的特性。分叉成功后,之前留存有比特币的地址上将按1:1的比例获赠同样数量的SBTC。

以太坊,以太币,token,AXCD,以太钱包

我在以太坊发了一个token

谁要想,给我以太钱包地址,免费赠送10个token

 

合约地址:0x8419bf9bAb3455756118Cb35709260B17C32F451

Token名:AXCD

长度:18

 

继续阅读以太坊,以太币,token,AXCD,以太钱包

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

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
由此可见该合约在我们的私有链上部署成功!