• ethereumjs/ethereumjs-account-1-简介和API


    https://github.com/ethereumjs/ethereumjs-account

    Encoding, decoding and validation of Ethereum's Account schema

    以太坊账户概要的编码、解码和验证

    账户 = 账户address + 账户状态

    这个库处理的是账户状态,然后将账户address作为key,账户状态作为value,添加到state前缀树中,即生成了一个账户

     

    SYNOPSIS概要

    This library eases the handling of Ethereum accounts, where accounts can be either external accounts or contracts (seeAccount Types docs).

    这个库简化了以太坊账户状态的处理,账户可以是外部账户(即我们日常使用的账户)或合约账户(即合约部署处)

    Note that the library is not meant to be used to handle your wallet accounts, use e.g. the web3-eth-personal package from the web3.js library for that. This is just a semantic wrapper to ease the use of account data and provide functionality for reading and writing accounts from and to the Ethereum state trie.

    注意这个库不意味着用来处理你的钱包账户,钱包账户应该使用来自web3.js库的web3-eth-personal包。这个只是用来简化账户数据的使用和提供从和给以太坊状态前缀树读写账户的函数的语义封装

    INSTALL安装

    npm install ethereumjs-account

    BROWSER浏览器

    This module work with browserify. 该模块browserify一起使用

    ⚠️账户 = 账户address + 账户状态

     这里的account = new Account(data)生成的是账户状态,最后还需要将其与某个address对应起来,对应的方法就是将其作为区块链的state merkle-Patricia树的key = address ,value = account.serialize()-即其的RLP序列化值,然后添加到前缀树中去,这样才真正生成了一个账户,如:

    stateTrie.put(address, account.serialize(), cb)

     

    API

    new Account([data])

    Creates a new account object创建一个账户对象

    • data - an account can be initialized with either a buffer containing the RLP serialized account. Or an Array of buffers relating to each of the account Properties, listed in order below. For example: 一个账户能够带着要么是包含着RLP编码的序列化账户的buffer,或者是关联每个账户属性,就像下面顺序列举一样的buffers数组来进行初始化
    var raw = [ //这个是数组格式的初始化
      '0x02', //nonce
      '0x0384', //balance
      '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', //stateRoot
      '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'  //codeHash
      ];
    
    var account = new Account(raw);

    Or lastly an Object containing the Properties of the account:

    下面这个例子就是包含着账户属性的对象

    var raw = {//这个是object对象格式的初始化
      nonce: '',
      balance: '0x03e7',
      stateRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
      codeHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'
    };
    
    var account = new Account(raw);

    For Object and Array each of the elements can either be a Buffer, hex String, Number, or an object with a toBuffer method such as Bignum.

    对于对象或者数组的每一个元素都要么是Buffer,十六进制字符串,数字,或者带着toBuffer方法的对象,如Bignum

     还有RLP编码的序列化格式:

    var account = new Account('f84602820384a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470')

    Account Properties 账户属性

    • nonce - The account's nonce.
    • balance - The account's balance in wei.
    • stateRoot - The stateRoot for the storage of the contract. 用于合约的存储的stateRoot
    • codeHash - The hash of the code of the contract. 合约代码的hash

    注意:如果是外部账户,它的codeHash为空字符串的hash值

     

    Account Methods账户方法

    account.isEmpty()

    Returns a Boolean determining if the account is empty.

    返回一个Boolean值,确定账户是否为空

    account.isContract() 看代码是怎么检测的

    Returns a Boolean deteremining if the account is a contract.

    返回一个Boolean值,确定账户是否为合约账户

    account.serialize()

    Returns the RLP serialization of the account as a Buffer.

    返回Buffer类型的账户的RLP编码序列化,得到的就是上面使用RLP编码的序列化格式方法进行初始化时的RLP序列化的值,如:

    'f84602820384a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'

    account.toJSON([object])

    Returns the account as JSON.

    返回JSON类型的账户

    • object - A Boolean that defaults to false. If object is true then this will return an Object, else it will return an Array. 默认为false的Boolean值。如果object为true,那么该方法将返回一个对象,否则他将返回一个数组


    account.getCode(trie, cb)

    Fetches the code from the trie.

    从前缀树中获取代码,得到的是账户中codeHash的值

    • trie - The trie storing the accounts. 存储账户的前缀树
    • cb - The callback. 回调函数

    account.setCode(trie, code, cb)

    Stores the code in the trie.

    在前缀树上存储代码。就是更改账户中codeHash的值,如果改后不为空字符串hash值,则相应存到前缀树的底层数据库

    • trie - The trie storing the accounts. 存储账户的前缀树
    • code - A Buffer. Buffer值的代码
    • cb - The callback. 回调函数

    Example for getCode and setCodegetCodesetCode方法的例子

    // Requires manual merkle-patricia-tree install
    const SecureTrie = require('merkle-patricia-tree/secure')
    const Account = require('./index.js')
    
    let code = Buffer.from('73095e7baea6a6c7c4c2dfeb977efac326af552d873173095e7baea6a6c7c4c2dfeb977efac326af552d873157', 'hex')
    
    let raw = {
      nonce: '',
      balance: '0x03e7',
      stateRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
      codeHash: '0xb30fb32201fe0486606ad451e1a61e2ae1748343cd3d411ed992ffcc0774edd4'
    }
    
    let account = new Account(raw)
    let trie = new SecureTrie()
    
    account.setCode(trie, code, function (err, codeHash) {
      console.log(`Code with hash 0x${codeHash.toString('hex')} set to trie`)
      account.getCode(trie, function (err, code) {//因为上面的setCode会对应更改account中的codeHash,当getCode时查找的就是account中的codeHash对应的code
        console.log(`Code ${code.toString('hex')} read from trie`)
      })
    })

    account.getStorage(trie, key, cb)

    Fetches key from the account's storage.

    从账户的存储中(即从前缀树中)获取key对应的值

    account.setStorage(trie, key, val, cb)

    Stores a val at the key in the contract's storage.

    在合约的存储中对应的key值处存储val值,会导致account的stateRoot值更改

    Example for getStorage and setStoragegetStoragesetStorage方法的例子

    // Requires manual merkle-patricia-tree install
    const SecureTrie = require('merkle-patricia-tree/secure')
    const Account = require('./index.js')
    
    let raw = {
      nonce: '',
      balance: '0x03e7',
      stateRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
      codeHash: '0xb30fb32201fe0486606ad451e1a61e2ae1748343cd3d411ed992ffcc0774edd4'
    }
    
    let account = new Account(raw)
    let trie = new SecureTrie()
    
    let key = Buffer.from('0000000000000000000000000000000000000000', 'hex')
    let value = Buffer.from('01', 'hex')
    
    account.setStorage(trie, key, value, function (err, value) {
      account.getStorage(trie, key, function (err, value) {
        console.log(`Value ${value.toString('hex')} set and retrieved from trie.`)
      })
    })

     更加详细的理解可看ethereumjs/ethereumjs-account-2-test

    实现代码:

    index.js

    const ethUtil = require('ethereumjs-util')
    const rlp = require('rlp')
    const Buffer = require('safe-buffer').Buffer
    
    var Account = module.exports = function (data) {
      // Define Properties,定义账户状态的属性
      var fields = [{
        name: 'nonce',
        default: Buffer.alloc(0)
      }, {
        name: 'balance',
        default: Buffer.alloc(0)
      }, {
        name: 'stateRoot',
        length: 32,
        default: ethUtil.SHA3_RLP
      }, {
        name: 'codeHash',
        length: 32,
        default: ethUtil.SHA3_NULL
      }]
    
      ethUtil.defineProperties(this, fields, data)
    }
    
    Account.prototype.serialize = function () {
      return rlp.encode(this.raw)
    }
    
    Account.prototype.isContract = function () {
      return this.codeHash.toString('hex') !== ethUtil.SHA3_NULL_S //即只要账户的codeHash值不是空字符串的hash值即可
    }
    
    Account.prototype.getCode = function (state, cb) {
      if (!this.isContract()) {//不是合约账户则返回0
        cb(null, Buffer.alloc(0))
        return
      }
    
      state.getRaw(this.codeHash, cb) //否则得到的是账户中codeHash的值
    }
    
    Account.prototype.setCode = function (trie, code, cb) {
      var self = this
    
      this.codeHash = ethUtil.sha3(code) //其实就是将账户中的codeHash改了
    
      if (this.codeHash.toString('hex') === ethUtil.SHA3_NULL_S) { //如果改了后发现codeHash值变成了空字符串的hash值
        cb(null, Buffer.alloc(0)) //则返回0的Buffer
        return
      }
    
      trie.putRaw(this.codeHash, code, function (err) { //如果不是空字符串的hash值,则设置key = codeHash,value = code存到树的底层数据库中
        cb(err, self.codeHash)
      })
    }
    
    Account.prototype.getStorage = function (trie, key, cb) {
      var t = trie.copy()
      t.root = this.stateRoot
      t.get(key, cb)
    }
    
    Account.prototype.setStorage = function (trie, key, val, cb) {
      var self = this
      var t = trie.copy()
      t.root = self.stateRoot
      t.put(key, val, function (err) {
        if (err) return cb()
        self.stateRoot = t.root //会导致stateRoot值更改
        cb()
      })
    }
    
    Account.prototype.isEmpty = function () {
      return this.balance.toString('hex') === '' &&
      this.nonce.toString('hex') === '' &&
      this.stateRoot.toString('hex') === ethUtil.SHA3_RLP_S &&
      this.codeHash.toString('hex') === ethUtil.SHA3_NULL_S
    }
     
     






  • 相关阅读:
    Linux命令行和Shell脚本编程
    Excel自动触发时间
    dom4j读取xml文件 简单例子
    GSM & Foxit Reader
    ThreadPoolExecutor 线程池
    Linux /var/log
    delphi开发技巧
    利用ScktSrvr打造多功能Socket服务器
    delphi中Windows消息大全使用详解
    自己构造注入点方便入侵
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/10101191.html
Copyright © 2020-2023  润新知