Welcome to MOAC documentation

9.1_转账

function send(chain3, fromAddress, fromSecret, toAddress, amount){
  var mc = chain3.mc;
  //使用fromAddress的交易数作为唯一按顺序的nonce
  var txCount = chain3.mc.getTransactionCount(fromAddress);

  //设置gas的价格
  var gasPrice = 2500000000;
  //设置gas的最大的数量
  var gasLimit = 40000;
  //从最小单位sha转成moac单位
  var value = chain3.toSha(amount, 'mc');

  //开始组装转帐交易
  var rawTx = {
    to: toAddress,
    nonce: chain3.intToHex(txCount),
    gasPrice: chain3.intToHex(gasPrice),
    gasLimit: chain3.intToHex(gasLimit),
    value: chain3.intToHex(value)
  };
  var tx = new chain3.transaction(rawTx);
  //设置转账交易的网络ID
  tx.setChainId(chain3.version.network);
  //打印出转账交易的JSON结构
  console.log('tx', tx.toJSON());

  //生成私钥的Buffer版本
  var privateKey = new Buffer(fromSecret, 'hex');
  //使用私钥对转账交易进行签名
  tx.sign(privateKey);

  //序列化签名后的转帐交易,准备发送
  var signedTx = '0x' + tx.serialize().toString('hex');

  //验证签名的转帐交易
  tx.verifySignature();
  var verify = '0x' + tx.getSenderAddress().toString('hex');
  console.log("verify address:", verify);

  //发送签名后的转帐交易到MOAC网络结点
  mc.sendRawTransaction(signedTx, function(err, hash) {
      if (!err){
          //成功后,返回交易的Hash
          //备注:这个成功只说明些交易被MOAC网络结点接受放到pending列表中
          console.log("succeed: ", hash);
          return hash;
      }else{
          console.log("error:", err);
      }
  });
}

9.2_创建帐户

使用console创建帐户

//输入密码后得到0x开头的字符串即为公钥账户(需要通过转换方可得到私钥)
personal.newAccount()

使用程序创建帐户

var crypto = require('crypto');
var secp256k1 = require('secp256k1');
var keccak = require('keccak');

//获得随机的32个字节作为私钥,在使用中,请注意随机数来源的安全
var privateKey = crypto.randomBytes(32);
//获得公钥
var publicKey = secp256k1.publicKeyCreate(privateKey, false).slice(1);
//获得地址
var address = keccak('keccak256').update(publicKey).digest().slice(-20);

console.log('public key', publicKey.toString('hex'));
console.log('private key', privateKey.toString('hex'));
console.log('address', '0x' + address.toString('hex'));

查询余额

function getBalance(chain3, address){
  var mc = chain3.mc;
  //获得帐户余额,以sha为单位
  var amountSha = mc.getBalance(address);
  //把sha为单位的余额转换成以moac为单位的余额
  var amountMC = chain3.fromSha(amountSha, 'mc');
  console.log(address + ":" + amountMC);
}

转帐

请参见转帐一节

9.3_交易所

// TODO 稍后更新

9.4_erc20代币说明

contract ERC20Token {
  //Token的名字,比如Bitcoin, Ethereum, Mother Of All Chain
  string  public name;
  //Token的符号或者叫代码, 比如BTC, ETH, MOAC
  string  public symbol;
  //Token使用的小数点后几位,比如6,表示分配一个token的数量为1000000
  uint    public decimals;
  //Token的总供应量
  uint256 public totalSupply;

  //返回_owner帐户的帐户余额,即Token数量
  function balanceOf(address _owner) public constant returns (uint256 balance);
  //转移_value的token数量到地址_to, 并且必须触发Transfer事件
  function transfer(address _to, uint256 _value) public returns (bool success);
  //从地址_from发送数量为_value的token到地址_to, 必须触发Transfer事件
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
  //允许_spender多次取回您的帐户最高达_value的token数量
  function approve(address _spender, uint256 _value) public returns (bool success);
  //_spender仍然被允许从_owner提取的token数量
  function allowance(address _owner, address _spender) public constant returns (uint256 remaining);
  //当token被转移(包括0值),必须被触发
  event Transfer(address indexed _from, address indexed _to, uint256 _value);
  //当任何成功调用approve(address _spender, uint256 _value)后,必须被触发
  event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

开发erc20代币智能合约

比如使用zeppelin库进行开发

pragma solidity ^0.4.18;

import "zeppelin-solidity/contracts/token/PausableToken.sol";

contract TestCoin is PausableToken {
  string public name = "Test";
  string public symbol = "TEST";
  uint public decimals = 6;
  uint public INITIAL_SUPPLY = 100000000 * (10 ** decimals);

  function TestCoin() public {
    totalSupply = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }
}

展开以后是这样的

pragma solidity ^0.4.13;

library SafeMath {
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

contract Ownable {
  address public owner;


  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);


  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function Ownable() public {
    owner = msg.sender;
  }


  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }


  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }

}

contract Pausable is Ownable {
  event Pause();
  event Unpause();

  bool public paused = false;


  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
  modifier whenNotPaused() {
    require(!paused);
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   */
  modifier whenPaused() {
    require(paused);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() onlyOwner whenNotPaused public {
    paused = true;
    Pause();
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() onlyOwner whenPaused public {
    paused = false;
    Unpause();
  }
}

contract ERC20Basic {
  uint256 public totalSupply;
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  */
  function transfer(address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[msg.sender]);

    // SafeMath.sub will throw if there is not enough balance.
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) public view returns (uint256 balance) {
    return balances[_owner];
  }

}

contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender) public view returns (uint256);
  function transferFrom(address from, address to, uint256 value) public returns (bool);
  function approve(address spender, uint256 value) public returns (bool);
  event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract StandardToken is ERC20, BasicToken {

  mapping (address => mapping (address => uint256)) internal allowed;


  /**
   * @dev Transfer tokens from one address to another
   * @param _from address The address which you want to send tokens from
   * @param _to address The address which you want to transfer to
   * @param _value uint256 the amount of tokens to be transferred
   */
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);

    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    Transfer(_from, _to, _value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   *
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param _spender The address which will spend the funds.
   * @param _value The amount of tokens to be spent.
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param _owner address The address which owns the funds.
   * @param _spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(address _owner, address _spender) public view returns (uint256) {
    return allowed[_owner][_spender];
  }

  /**
   * @dev Increase the amount of tokens that an owner allowed to a spender.
   *
   * approve should be called when allowed[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param _spender The address which will spend the funds.
   * @param _addedValue The amount of tokens to increase the allowance by.
   */
  function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
    allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
    Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner allowed to a spender.
   *
   * approve should be called when allowed[_spender] == 0. To decrement
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param _spender The address which will spend the funds.
   * @param _subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
    uint oldValue = allowed[msg.sender][_spender];
    if (_subtractedValue > oldValue) {
      allowed[msg.sender][_spender] = 0;
    } else {
      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    }
    Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

}

contract PausableToken is StandardToken, Pausable {

  function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) {
    return super.transfer(_to, _value);
  }

  function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) {
    return super.transferFrom(_from, _to, _value);
  }

  function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) {
    return super.approve(_spender, _value);
  }

  function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) {
    return super.increaseApproval(_spender, _addedValue);
  }

  function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) {
    return super.decreaseApproval(_spender, _subtractedValue);
  }
}

contract TestCoin is PausableToken {
  string public name = "Test Coin";
  string public symbol = "TEST";
  uint public decimals = 6;
  uint public INITIAL_SUPPLY = 100000000 * (10 ** decimals);

  function TestCoin() public {
    totalSupply = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }
}

或者直接进行开发

pragma solidity ^0.4.16;

contract ERC20Token {
  uint256 public totalSupply;

  function balanceOf(address _owner) public constant returns (uint256 balance);
  function transfer(address _to, uint256 _value) public returns (bool success);
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);

  function approve(address _spender, uint256 _value) public returns (bool success);

  function allowance(address _owner, address _spender) public constant returns (uint256 remaining);

  event Transfer(address indexed _from, address indexed _to, uint256 _value);
  event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

contract TestToken is ERC20Token {

  string  public name = "Test Coin";
  string  public symbol = "TEST";
  uint8   public decimals = 6;
  uint256 public INITIAL_SUPPLY = 100000000 * (10 ** uint256(decimals));

  mapping (address => uint256) balances;
  mapping (address => mapping (address => uint256)) allowed;

  constructor() public {
    totalSupply = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }

  function transfer(address _to, uint256 _value) public returns (bool success) {
    require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
    require(_to != 0x0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
    balances[_to] += _value;
    balances[_from] -= _value;
    allowed[_from][msg.sender] -= _value;
    emit Transfer(_from, _to, _value);
    return true;
  }

  function balanceOf(address _owner) public constant returns (uint256 balance) {
    return balances[_owner];
  }

  function approve(address _spender, uint256 _value) public returns (bool success) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }
}

编译erc20代币智能合约,生成abi及bytecode

使用remix编译

复制abi及bytecode以便下一步创建智能合约

[
  {
    "constant": true,
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_spender",
        "type": "address"
      },
      {
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "name": "success",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_from",
        "type": "address"
      },
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "name": "success",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "INITIAL_SUPPLY",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "name": "",
        "type": "uint8"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [],
    "name": "TestCoin",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "name": "balance",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "name": "success",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      },
      {
        "name": "_spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "name": "remaining",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "_from",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "_to",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "_owner",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "_spender",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  }
]

bytecode为

60606040526040805190810160405280600981526020017f5465737420436f696e00000000000000000000000000000000000000000000008152506001908051906020019061004f9291906100e7565b506040805190810160405280600481526020017f54455354000000000000000000000000000000000000000000000000000000008152506002908051906020019061009b9291906100e7565b506006600360006101000a81548160ff021916908360ff160217905550600360009054906101000a900460ff1660ff16600a0a6305f5e1000260045534156100e257600080fd5b61018c565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012857805160ff1916838001178555610156565b82800160010185558215610156579182015b8281111561015557825182559160200191906001019061013a565b5b5090506101639190610167565b5090565b61018991905b8082111561018557600081600090555060010161016d565b5090565b90565b610c5c8061019b6000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c55780632ff2e9dc1461023e578063313ce56714610267578063410e7b421461029657806370a08231146102ab57806395d89b41146102f8578063a9059cbb14610386578063dd62ed3e146103e0575b600080fd5b34156100bf57600080fd5b6100c761044c565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506104ea565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af6105dc565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506105e2565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b61025161084e565b6040518082815260200191505060405180910390f35b341561027257600080fd5b61027a610854565b604051808260ff1660ff16815260200191505060405180910390f35b34156102a157600080fd5b6102a9610867565b005b34156102b657600080fd5b6102e2600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108b8565b6040518082815260200191505060405180910390f35b341561030357600080fd5b61030b610901565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561034b578082015181840152602081019050610330565b50505050905090810190601f1680156103785780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561039157600080fd5b6103c6600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061099f565b604051808215151515815260200191505060405180910390f35b34156103eb57600080fd5b610436600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610ba9565b6040518082815260200191505060405180910390f35b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104e25780601f106104b7576101008083540402835291602001916104e2565b820191906000526020600020905b8154815290600101906020018083116104c557829003601f168201915b505050505081565b600081600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600081600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101580156106af575081600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b15156106ba57600080fd5b81600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b60045481565b600360009054906101000a900460ff1681565b600454600081905550600454600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109975780601f1061096c57610100808354040283529160200191610997565b820191906000526020600020905b81548152906001019060200180831161097a57829003601f168201915b505050505081565b600081600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610a6f5750600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401115b1515610a7a57600080fd5b60008373ffffffffffffffffffffffffffffffffffffffff1614151515610aa057600080fd5b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a723058204eb2d8db44d1baf9e40dfa6641ad7d3320d483efe196f35150c97c3e2097dbbc0029

命令行使用solc编译

运行如下命令,输出TestToken.abi及TestToken.bin到bin目录下,TestToken.abi里边放的就是abi的内容,TestToken.bin里边放的就是bytecode的内容。

solc --bin --abi -o bin TestToken.sol

程序中使用solc编译

var fs = require('fs');
var solc = require('solc');

var cmds = process.argv;
if(cmds != null && cmds.length > 2){
  var file = cmds[2];
  var name = cmds[3];
  var content = fs.readFileSync(file).toString();

  var input = {
    file: content
  };

  var output = solc.compile({sources: input}, 1);
  console.log('contracts', Object.keys(output.contracts));

  var ctt = output.contracts[name];
  if(ctt == null){
      return;
  }

  var bytecode = ctt.bytecode;
  var abi = JSON.parse(ctt.interface);

  console.log('bytecode', bytecode);
  console.log('abi', ctt.interface);
}

部署erc20代币智能合约

function createContract(chain3, account, abiString, bytecodeString){
    var bytecode = "0x" + bytecodeString;
    var abi = JSON.parse(abiString);

    console.log('bytecode', bytecode);
    console.log('abi', abiString);

    var gasValue = chain3.mc.estimateGas({data: bytecode});
    console.log("gas estimate on contract:", gasValue);

    var address = account.address;
    var secret = account.secret;

    var txCount = chain3.mc.getTransactionCount(address);
    console.log("get tx account", txCount)

    var rawTx = {
      from: address,
      nonce: chain3.intToHex(txCount),
      gasPrice: chain3.intToHex(25000000000),
      gasLimit: chain3.intToHex(gasValue * 10), //"* 10", 具体原因可查看 https://github.com/MOACChain/moac-core/issues/6, 后续问题修复后从文档中移掉 "* 10"
      value: '0x00',
      data: bytecode
    };

    console.log('raw tx:', rawTx);
    var tx = new chain3.transaction(rawTx);
    console.log('version:', chain3.version.network);
    tx.setChainId(chain3.version.network);
    console.log("tx chain id:", tx.getChainId())

    //Requires the private key
    var privateKey = new Buffer(secret, 'hex');
    console.log(tx.toJSON());

    tx.sign(privateKey);
    console.log("after signed:", tx.toJSON());

    var signedTx = '0x' + tx.serialize().toString('hex');
    console.log("send signed tx:", signedTx);
    console.log("len", signedTx.length);

    tx.verifySignature();
    var recover = '0x' + tx.getSenderAddress().toString('hex');
    console.log("recovered address:", recover);

    chain3.mc.sendRawTransaction(signedTx, function(err, hash) {
        if (!err){
          console.log("succeed: ", hash);
          //等合约创建完成,返回合约地址
          var filter = chain3.mc.filter('latest');
          filter.watch(function(error, result) {
            var receipt = chain3.mc.getTransactionReceipt(hash);
            if (!error && receipt && receipt.transactionHash == hash) {
              console.log("contract address: ", receipt && receipt.contractAddress);
              filter.stopWatching();
            }
          });
        }else{
            console.log("error:", err.message);
        }
    });
}

调用erc20代币智能合约

一种方法是通过abi生成智能合约对象, 直接通过对应合约方法进行call调用,如下例子说明查询erc20代币相应帐户对应的代币数量的例子.

function callContract(chain3, contractAddress, address, abiString){
  var abi = JSON.parse(abiString);
  var contract = chain3.mc.contract(abi);
  var token = contract.at(contractAddress);
  token.balanceOf.call(address, function(err, result){
    console.log(err, result);
  });
}

另外一种方法通过对交易签名进行调用,如下例子说明调用erc20代币的转帐交易的方法

function callContract(chain3, account, contractAddress, address, abiString){
  var abi = JSON.parse(abiString);
  var contract = chain3.mc.contract(abi);
  var token = contract.at(contractAddress);

  console.log('data', token.balanceOf.getData(address));
  var privateKey = new Buffer(account.secret, "hex");
  var txCount = chain3.mc.getTransactionCount(account.address);
  var rawTx = {
    nonce: chain3.intToHex(txCount),
    gasPrice: chain3.intToHex(25000000000),
    gasLimit: chain3.intToHex(40000),
    to: contractAddress,
    data: token.transfer.getData(destinate, 100),
  };
  var tx = new chain3.transaction(rawTx);
  tx.setChainId(chain3.version.network);
  tx.sign(privateKey);
  var signedTx = '0x' + tx.serialize().toString('hex');
  chain3.mc.sendRawTransaction(signedTx, function(err, hash) {
      if (!err){
          console.log("succeed: ", hash);
      }else{
          console.log("error:", err.message);
      }
  });
}

9.5_发行erc721通证

// TODO 稍后更新

How to Access Your Wallet

After you have created your wallet, we want to make sure that we can access this wallet, now and in the future.

If you can successfully unlock your wallet and send MOAC out of the wallet, you can rest assured that you will have access to any funds you send to it.

Accessing your Wallet

Navigate to the Send Page.

Select your keystore file or your private key.

If the wallet is encrypted, a text box will automatically appear. Enter the password.

Click the Unlock Wallet button.

Your wallet information should show up.

Find your account address, next to a colorful, circular icon. This icon visually represents your address.

If you printed out your wallet, check to be sure the circles match. They should be the same colors, and shapes. Otherwise, something went wrong and you should start over.

You can share your address with others so they can send you MOAC. Your account will not be compromised, just make sure to send them your PUBLIC wallet address and not your private key.

TIP: If you are planning on holding a large amount of MOAC, we recommend you send a small amount to test first, before depositing a large amount.

The Future

While we used the Send page to access your wallet this time, it is not recommended that you do so in the future. You only need your address in order to see your balance. Do not enter your private key anywhere if you just want to check the balance or see incoming and outgoing transactions.

Instead, search your address (or bookmark it) on http://explorer.moac.io/.

While you are at it, you should bookmark https://www.moacwalletonline/ as well.

MoacWalletOnle is a client-side wallet, which means you hold your own keys. If someone gets your private key (keystore file, mnemonic, passwords), they have complete access to your funds. There is no stopping transactions, canceling transactions, or resetting passwords. Once a transaction is on the blockchain, it’s final.

For this reason, it is very, very important to keep your private key a secret and use it as rarely as possible. Only enter it on sites after double-checking to be sure you are on the correct site.

Chain3 JavaScript API

Chain3 JavaScript API was built for MOAC chain. It followed the Ethereum web3.js API routines so the users can easily move their Ðapp to MOAC chain.

To make a Ðapp work on MOAC network, user should use the chain3 object provided by the chain3.js library. It communicates to a local MOAC node through RPC calls. chain3.js works with any MOAC node, which exposes an RPC layer.

chain3 contains the mc object - chain3.mc (for MOAC blockchain VNODE interactions) and account.js (for transaction signing). Over time we’ll introduce other objects such as SCS for the other chain3 protocols. Working examples can be found here.

Using callbacks

As this API is designed to work with a local RPC node and all its functions are by default use synchronous HTTP requests.con

If you want to make an asynchronous request, you can pass an optional callback as the last parameter to most functions. All callbacks are using an error first callback style:

chain3.mc.getBlock(48, function(error, result){
    if(!error)
        console.log(result)
    else
        console.error(error);
})

Batch requests

Batch requests allow queuing up requests and processing them at once.

var batch = chain3.createBatch();
batch.add(chain3.mc.getBalance.request('0x0000000000000000000000000000000000000000', 'latest', callback));
batch.add(chain3.mc.contract(abi).at(address).balance.request(address, callback2));
batch.execute();

A note on big numbers in chain3.js

You will always get a BigNumber object for balance values as JavaScript is not able to handle big numbers correctly. Look at the following examples:

"101010100324325345346456456456456456456"
// "101010100324325345346456456456456456456"
101010100324325345346456456456456456456
// 1.0101010032432535e+38

chain3.js depends on the BigNumber Library and adds it automatically.

var balance = new BigNumber('123456786979284780000000000');
// or var balance = chain3.mc.getBalance(someAddress);

balance.plus(21).toString(10); // toString(10) converts it to a number string
// "123456786979284780000000021"

The next example wouldn’t work as we have more than 20 floating points, therefore it is recommended that you always keep your balance in sha and only transform it to other units when presenting to the user:

var balance = new BigNumber('13124.234435346456466666457455567456');

balance.plus(21).toString(10); // toString(10) converts it to a number string, but can only show max 20 floating points
// "13145.23443534645646666646" // you number would be cut after the 20 floating point

Chain3 Javascript Ðapp API Reference

Usage

chain3.version.api

The chain3 object provides all methods.

Example
var Chain3 = require('chain3');
// create an instance of chain3 using the HTTP provider.
var chain3 = new Chain3(new Chain3.providers.HttpProvider("http://localhost:8545"));

chain3.version.api

chain3.version.api
// or async
chain3.version.getApi(callback(error, result){ ... })
Returns

String - The moac js api version.

Example
var version = chain3.version.api;
console.log(version); // "0.2.0"

chain3.version.node

chain3.version.node
// or async
chain3.version.getClient(callback(error, result){ ... })
Returns

String - The client/node version.

Example
var version = chain3.version.node;
console.log(version); // "Moac/v0.1.0-develop/darwin-amd64/go1.9"

chain3.version.network

chain3.version.network
// or async
chain3.version.getNetwork(callback(error, result){ ... })
Returns

String - The network protocol version.

Example
var version = chain3.version.network;
console.log(version); // 54

chain3.version.moac

chain3.version.moac
// or async
chain3.version.getMoac(callback(error, result){ ... })
Returns

String - The moac protocol version.

Example
var version = chain3.version.moac;
console.log(version); // 0x3f

chain3.isConnected

chain3.isConnected()

Should be called to check if a connection to a node exists

Parameters

none

Returns

Boolean

Example
if(!chain3.isConnected()) {

   // show some dialog to ask the user to start a node

} else {

   // start chain3 filters, calls, etc

}

chain3.setProvider

chain3.setProvider(provider)

Should be called to set provider.

Parameters

none

Returns

undefined

Example
chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545')); // 8545 for go/moac

chain3.currentProvider

chain3.currentProvider

Will contain the current provider, if one is set. This can be used to check if moac etc. set already a provider.

Returns

Object - The provider set or null;

Example
// Check if moac etc. already set a provider
if(!chain3.currentProvider)
    chain3.setProvider(new chain3.providers.HttpProvider("http://localhost:8545"));

chain3.reset

chain3.reset(keepIsSyncing)

Should be called to reset state of chain3. Resets everything except manager. Uninstalls all filters. Stops polling.

Parameters
  1. Boolean - If true it will uninstall all filters, but will keep the chain3.mc.isSyncing() polls
Returns

undefined

Example
chain3.reset();

chain3.sha3

chain3.sha3(string [, callback])
Parameters
  1. String - The string to hash using the SHA3 algorithm
  2. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

String - The SHA3 of the given data.

Example
var str = chain3.sha3("Some ASCII string to be hashed in MOAC");
console.log(str); // "0xbfa24877cd68e6734710402a2af3e29cf18bd6d2f304aa528ffa3a32fa7652d2"

chain3.toHex

chain3.toHex(mixed);

Converts any value into HEX.

Parameters
  1. String|Number|Object|Array|BigNumber - The value to parse to HEX. If its an object or array it will be JSON.stringify first. If its a BigNumber it will make it the HEX value of a number.
Returns

String - The hex string of mixed.

Example
var str = chain3.toHex("moac network");
console.log(str); // '0x6d6f6163206e6574776f726b'

console.log(chain3.toHex({moac: 'test'}));
//'0x7b226d6f6163223a2274657374227d'

chain3.toAscii

chain3.toAscii
chain3.toAscii(hexString);

Converts a HEX string into a ASCII string.

Parameters
  1. String - A HEX string to be converted to ascii.
Returns

String - An ASCII string made from the given hexString.

Example
var str = chain3.toAscii("0x0x6d6f6163206e6574776f726b");
console.log(str); // "moac network"

chain3.fromAscii

chain3.fromAscii(string);

Converts any ASCII string to a HEX string.

Parameters

String - An ASCII string to be converted to HEX.

Returns

String - The converted HEX string.

Example
var str = chain3.fromAscii('moac network');
console.log(str); // "0x6d6f6163206e6574776f726b"

chain3.toChecksumAddress

chain3.toChecksumAddress(hexString);

Converts a string to the checksummed address equivalent.

Parameters
  1. String - A string to be converted to a checksummed address.
Returns

String - A string containing the checksummed address.

Example
var myAddress = chain3.toChecksumAddress('0xa0c876ec9f2d817c4304a727536f36363840c02c');
console.log(myAddress); // '0xA0C876eC9F2d817c4304A727536f36363840c02c'

chain3.toDecimal

chain3.toDecimal(hexString);

Converts a HEX string to its number representation.

Parameters
  1. String - An HEX string to be converted to a number.
Returns

Number - The number representing the data hexString.

Example
var number = chain3.toDecimal('0x15');
console.log(number); // 21

chain3.fromDecimal

chain3.fromDecimal(number);

Converts a number or number string to its HEX representation.

Parameters
  1. Number|String - A number to be converted to a HEX string.
Returns

String - The HEX string representing of the given number.

Example
var value = chain3.fromDecimal('21');
console.log(value); // "0x15"

chain3.fromSha

chain3.fromSha(number, unit)

Converts a number of sha into the following moac units:

  • ksha/femtomc
  • msha/picomc
  • gsha/nano/xiao
  • micro/sand
  • milli
  • mc
  • kmc/grand
  • mmc
  • gmc
  • tmc
Parameters
  1. Number|String|BigNumber - A number or BigNumber instance.
  2. String - One of the above moac units.
Returns

String|BigNumber - Either a number string, or a BigNumber instance, depending on the given number parameter.

Example
var value = chain3.fromSha('21000000000000', 'Xiao');
console.log(value); // "21000"

chain3.toSha

chain3.toSha(number, unit)

Converts a moac unit into sha. Possible units are:

  • ksha/femtomc
  • msha/picomc
  • gsha/nano/xiao
  • micro/sand
  • milli
  • mc
  • kmc/grand
  • mmc
  • gmc
  • tmc
Parameters
  1. Number|String|BigNumber - A number or BigNumber instance.
  2. String - One of the above moac units.
Returns

String|BigNumber - Either a number string, or a BigNumber instance, depending on the given number parameter.

Example
var value = chain3.toSha('1', 'mc');
console.log(value); // "1000000000000000000" = 1e18

chain3.toBigNumber

chain3.toBigNumber(numberOrHexString);

Converts a given number into a BigNumber instance.

See the note on BigNumber.

Parameters
  1. Number|String - A number, number string or HEX string of a number.
Returns

BigNumber - A BigNumber instance representing the given value.

Example
var value = chain3.toBigNumber('200000000000000000000001');
console.log(value); // instanceOf BigNumber, { [String: '2.00000000000000000000001e+23'] s: 1, e: 23, c: [ 2000000000, 1 ] }
console.log(value.toNumber()); // 2.0000000000000002e+23
console.log(value.toString(10)); // '200000000000000000000001'

chain3.net

chain3.net.listening

chain3.net.listening
// or async
chain3.net.getListening(callback(error, result){ ... })

This property is read only and says whether the node is actively listening for network connections or not.

Returns

Boolean - true if the client is actively listening for network connections, otherwise false.

Example
var listening = chain3.net.listening;
console.log(listening); // true of false

chain3.net.peerCount

chain3.net.peerCount
// or async
chain3.net.getPeerCount(callback(error, result){ ... })

This property is read only and returns the number of connected peers.

Returns

Number - The number of peers currently connected to the client.

Example
var peerCount = chain3.net.peerCount;
console.log(peerCount); // 4

chain3.mc

Contains the MOAC blockchain related methods.

Example
var mc = chain3.mc;

chain3.mc.defaultAccount

chain3.mc.defaultAccount

This default address is used for the following methods (optionally you can overwrite it by specifying the from property):

Values

String, 20 Bytes - Any address you own, or where you have the private key for.

Default is undefined.

Returns

String, 20 Bytes - The currently set default address.

Example
var defaultAccount = chain3.mc.defaultAccount;
console.log(defaultAccount); // 'undefined'

// set the default block
chain3.mc.defaultAccount = '0x8888f1f195afa192cfee860698584c030f4c9db1';
console.log(chain3.mc.defaultAccount);//'0x8888f1f195afa192cfee860698584c030f4c9db1'

chain3.mc.defaultBlock

chain3.mc.defaultBlock

This default block is used for the following methods (optionally you can overwrite the defaultBlock by passing it as the last parameter):

Values

Default block parameters can be one of the following:

  • Number - a block number
  • String - "earliest", the genisis block
  • String - "latest", the latest block (current head of the blockchain)
  • String - "pending", the currently mined block (including pending transactions)

Default is latest

Returns

Number|String - The default block number to use when querying a state.

Example
var defaultBlock = chain3.mc.defaultBlock;
console.log(defaultBlock); // 'latest'

// set the default block
chain3.mc.defaultBlock = 12345;
console.log(chain3.mc.defaultAccount);//'12345'

chain3.mc.syncing

chain3.mc.syncing
// or async
chain3.mc.getSyncing(callback(error, result){ ... })

This property is read only and returns the either a sync object, when the node is syncing or false.

Returns

Object|Boolean - A sync object as follows, when the node is currently syncing or false: - startingBlock: Number - The block number where the sync started. - currentBlock: Number - The block number where at which block the node currently synced to already. - highestBlock: Number - The estimated block number to sync to.

Example
var sync = chain3.mc.syncing;
console.log(sync);
/*
{
   startingBlock: 300,
   currentBlock: 312,
   highestBlock: 512
}
*/

chain3.mc.isSyncing

chain3.mc.isSyncing(callback);

This convenience function calls the callback everytime a sync starts, updates and stops.

Returns

Object - a isSyncing object with the following methods:

  • syncing.addCallback(): Adds another callback, which will be called when the node starts or stops syncing.
  • syncing.stopWatching(): Stops the syncing callbacks.
Callback return value
  • Boolean - The callback will be fired with true when the syncing starts and with false when it stopped.
  • Object - While syncing it will return the syncing object:
  • startingBlock: Number - The block number where the sync started.
  • currentBlock: Number - The block number where at which block the node currently synced to already.
  • highestBlock: Number - The estimated block number to sync to.
Example
chain3.mc.isSyncing(function(error, sync){
    if(!error) {
        // stop all app activity
        if(sync === true) {
           // we use `true`, so it stops all filters, but not the chain3.mc.syncing polling
           chain3.reset(true);

        // show sync info
        } else if(sync) {
           console.log(sync.currentBlock);

        // re-gain app operation
        } else {
            // run your app init function...
        }
    }
});

chain3.mc.coinbase

chain3.mc.coinbase
// or async
chain3.mc.getCoinbase(callback(error, result){ ... })

This property is read only and returns the coinbase address were the mining rewards go to.

Returns

String - The coinbase address of the client.

Example
var coinbase = chain3.mc.coinbase;
console.log(coinbase); // "0x407d73d8a49eeb85d32cf465507dd71d507100c1"

chain3.mc.mining

chain3.mc.mining
// or async
chain3.mc.getMining(callback(error, result){ ... })

This property is read only and says whether the node is mining or not.

Returns

Boolean - true if the client is mining, otherwise false.

Example
var mining = chain3.mc.mining;
console.log(mining); // true or false

chain3.mc.hashrate

chain3.mc.hashrate
// or async
chain3.mc.getHashrate(callback(error, result){ ... })

This property is read only and returns the number of hashes per second that the node is mining with.

Returns

Number - number of hashes per second.

Example
var hashrate = chain3.mc.hashrate;
console.log(hashrate); // 493736

chain3.mc.gasPrice

chain3.mc.gasPrice
// or async
chain3.mc.getGasPrice(callback(error, result){ ... })

This property is read only and returns the current gas price. The gas price is determined by the x latest blocks median gas price.

Returns

BigNumber - A BigNumber instance of the current gas price in sha.

See the note on BigNumber.

Example
var gasPrice = chain3.mc.gasPrice;
console.log(gasPrice.toString(10)); // "20000000000"

chain3.mc.accounts

chain3.mc.accounts
// or async
chain3.mc.getAccounts(callback(error, result){ ... })

This property is read only and returns a list of accounts the node controls.

Returns

Array - An array of addresses controlled by client.

Example
var accounts = chain3.mc.accounts;
console.log(accounts); // ["0x407d73d8a49eeb85d32cf465507dd71d507100c1"]

chain3.mc.blockNumber

chain3.mc.blockNumber
// or async
chain3.mc.getBlockNumber(callback(error, result){ ... })

This property is read only and returns the current block number.

Returns

Number - The number of the most recent block.

Example
var number = chain3.mc.blockNumber;
console.log(number); // 2744

chain3.mc.getBalance

chain3.mc.getBalance(addressHexString [, defaultBlock] [, callback])

Get the balance of an address at a given block.

Parameters
  1. String - The address to get the balance of.
  2. Number|String - (optional) If you pass this parameter it will not use the default block set with chain3.mc.defaultBlock.
  3. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

String - A BigNumber instance of the current balance for the given address in sha.

See the note on BigNumber.

Example
var balance = chain3.mc.getBalance("0x407d73d8a49eeb85d32cf465507dd71d507100c1");
console.log(balance); // instanceof BigNumber
console.log(balance.toString(10)); // '1000000000000'
console.log(balance.toNumber()); // 1000000000000

chain3.mc.getStorageAt

chain3.mc.getStorageAt(addressHexString, position [, defaultBlock] [, callback])

Get the storage at a specific position of an address.

Parameters
  1. String - The address to get the storage from.
  2. Number - The index position of the storage.
  3. Number|String - (optional) If you pass this parameter it will not use the default block set with chain3.mc.defaultBlock.
  4. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

String - The value in storage at the given position.

Example
var state = chain3.mc.getStorageAt("0x407d73d8a49eeb85d32cf465507dd71d507100c1", 0);
console.log(state); // "0x03"

chain3.mc.getCode

chain3.mc.getCode(addressHexString [, defaultBlock] [, callback])

Get the code at a specific address. For a contract address, return the binary code of the contract.

Parameters
  1. String - The address to get the code from.
  2. Number|String - (optional) If you pass this parameter it will not use the default block set with chain3.mc.defaultBlock.
  3. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

String - The data at given address addressHexString.

Example
var code = chain3.mc.getCode("0x1d12aec505caa2b8513cdad9a13e9d4806a1b704");
console.log(code); // "0x600160008035811a818181146012578301005b601b6001356025565b8060005260206000f25b600060078202905091905056"

chain3.mc.getBlock

chain3.mc.getBlock(blockHashOrBlockNumber [, returnTransactionObjects] [, callback])

Returns a block matching the block number or block hash.

Parameters
  1. String|Number - The block number or hash. Or the string "earliest", "latest" or "pending" as in the default block parameter.
  2. Boolean - (optional, default false) If true, the returned block will contain all transactions as objects, if false it will only contains the transaction hashes.
  3. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

Object - The block object:

  • number: Number - the block number. null when its pending block.
  • hash: String, 32 Bytes - hash of the block. null when its pending block.
  • parentHash: String, 32 Bytes - hash of the parent block.
  • nonce: String, 8 Bytes - hash of the generated proof-of-work. null when its pending block.
  • sha3Uncles: String, 32 Bytes - SHA3 of the uncles data in the block.
  • logsBloom: String, 256 Bytes - the bloom filter for the logs of the block. null when its pending block.
  • transactionsRoot: String, 32 Bytes - the root of the transaction trie of the block
  • stateRoot: String, 32 Bytes - the root of the final state trie of the block.
  • miner: String, 20 Bytes - the address of the beneficiary to whom the mining rewards were given.
  • difficulty: BigNumber - integer of the difficulty for this block.
  • totalDifficulty: BigNumber - integer of the total difficulty of the chain until this block.
  • extraData: String - the “extra data” field of this block.
  • size: Number - integer the size of this block in bytes.
  • gasLimit: Number - the maximum gas allowed in this block.
  • gasUsed: Number - the total used gas by all transactions in this block.
  • timestamp: Number - the unix timestamp for when the block was collated.
  • transactions: Array - Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter.
  • uncles: Array - Array of uncle hashes.
Example
var info = chain3.mc.getBlock(0);
console.log(info);
/*
{ difficulty: { [String: '100000000000'] s: 1, e: 11, c: [ 100000000000 ] },
  extraData: '0x31393639415250414e4554373354435049503039425443323031384d4f4143',
  gasLimit: 9000000,
  gasUsed: 0,
  hash: '0x6b9661646439fab926ffc9bccdf3abb572d5209ae59e3390abf76aee4e2d49cd',
  logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
  miner: '0x0000000000000000000000000000000000000000',
  mixHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  nonce: '0x0000000000000042',
  number: 0,
  parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  receiptsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
  size: 540,
  stateRoot: '0xe221c9e4ad19514d7ce3e6b0bec3ad7f6cc293336e59c301cda293cfbda83df6',
  timestamp: 0,
  totalDifficulty: { [String: '100000000000'] s: 1, e: 11, c: [ 100000000000 ] },
  transactions: [],
  transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  uncles: [] }
*/

chain3.mc.getBlockTransactionCount

chain3.mc.getBlockTransactionCount(hashStringOrBlockNumber [, callback])

Returns the number of transaction in a given block.

Parameters
  1. String|Number - The block number or hash. Or the string "earliest", "latest" or "pending" as in the default block parameter.
  2. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

Number - The number of transactions in the given block.

Example
var number = chain3.mc.getBlockTransactionCount("0xddfb8508bff841242099e640efe59f5e5252be1a60fa701d333e1a8bfdee6263");
console.log(number); // 1

chain3.mc.getUncle

chain3.mc.getUncle(blockHashStringOrNumber, uncleNumber [, returnTransactionObjects] [, callback])

Returns a blocks uncle by a given uncle index position.

Parameters
  1. String|Number - The block number or hash. Or the string "earliest", "latest" or "pending" as in the default block parameter.
  2. Number - The index position of the uncle.
  3. Boolean - (optional, default false) If true, the returned block will contain all transactions as objects, if false it will only contains the transaction hashes.
  4. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

Object - the returned uncle. For a return value see chain3.mc.getBlock().

Note: An uncle doesn’t contain individual transactions.

Example
var uncle = chain3.mc.getUncle(500, 0);
console.log(uncle); // see chain3.mc.getBlock

chain3.mc.getTransaction

chain3.mc.getTransaction(transactionHash [, callback])

Returns a transaction matching the given transaction hash.

Parameters
  1. String - The transaction hash.
  2. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

Object - A transaction object its hash transactionHash:

  • hash: String, 32 Bytes - hash of the transaction.
  • nonce: Number - the number of transactions made by the sender prior to this one.
  • blockHash: String, 32 Bytes - hash of the block where this transaction was in. null when its pending.
  • blockNumber: Number - block number where this transaction was in. null when its pending.
  • transactionIndex: Number - integer of the transactions index position in the block. null when its pending.
  • from: String, 20 Bytes - address of the sender.
  • to: String, 20 Bytes - address of the receiver. null when its a contract creation transaction.
  • value: BigNumber - value transferred in Sha.
  • gasPrice: BigNumber - gas price provided by the sender in Sha.
  • gas: Number - gas provided by the sender.
  • input: String - the data sent along with the transaction.
Example
var txhash = "0x687751dd47684f4b5df263ae4ec39f54f057d0e2a1dde56f9d52766849c9c7fe";

var transaction = chain3.mc.getTransaction(txhash);
console.log(transaction);
/*
{ blockHash: '0x716c602d49055b4e24fbe7da952c1ad81820ad0401f3cb3ce12e832fbcc368f5',
  blockNumber: 57259,
  from: '0x7cfd775c7a97aa632846eff35dcf9dbcf502d0f3',
  gas: 1000,
  gasPrice: { [String: '200000000000'] s: 1, e: 11, c: [ 200000000000 ] },
  hash: '0xf1c1771204431c1c584e793b49d41586a923c370be93673aac42d66252bc8d0a',
  input: '0x',
  nonce: 840,
  syscnt: '0x0',
  to: '0x3435410589ebd06b74079a1e141759d8502aeb8b',
  transactionIndex: 689,
  value: { [String: '1000000000'] s: 1, e: 9, c: [ 1000000000 ] },
  v: '0xea',
  r: '0x77aa72d0900e436b60f8be377e43dead3567241a85fbeb5517283e2dc8aca2b4',
  s: '0x24477ec130fc4101289b37e6107acfe64026c898994273110faa8f19b8ea6985',
  shardingFlag: '0x0' }
*/

chain3.mc.getTransactionFromBlock

getTransactionFromBlock(hashStringOrNumber, indexNumber [, callback])

Returns a transaction based on a block hash or number and the transactions index position.

Parameters
  1. String - A block number or hash. Or the string "earliest", "latest" or "pending" as in the default block parameter.
  2. Number - The transactions index position.
  3. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

Object - A transaction object, see chain3.mc.getTransaction:

Example
var transaction = chain3.mc.getTransactionFromBlock(921, 2);
console.log(transaction); // see chain3.mc.getTransaction

chain3.mc.getTransactionReceipt

chain3.mc.getTransactionReceipt(hashString [, callback])

Returns the receipt of a transaction by transaction hash.

Note That the receipt is not available for pending transactions.

Parameters
  1. String - The transaction hash.
  2. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

Object - A transaction receipt object, or null when no receipt was found:

  • blockHash: String, 32 Bytes - hash of the block where this transaction was in.
  • blockNumber: Number - block number where this transaction was in.
  • transactionHash: String, 32 Bytes - hash of the transaction.
  • transactionIndex: Number - integer of the transactions index position in the block.
  • from: String, 20 Bytes - address of the sender.
  • to: String, 20 Bytes - address of the receiver. null when its a contract creation transaction.
  • cumulativeGasUsed: Number - The total amount of gas used when this transaction was executed in the block.
  • gasUsed: Number - The amount of gas used by this specific transaction alone.
  • contractAddress: String - 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null.
  • logs: Array - Array of log objects, which this transaction generated.
Example
var receipt = chain3.mc.getTransactionReceipt('0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b');
console.log(receipt);
{
  "transactionHash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b",
  "transactionIndex": 0,
  "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46",
  "blockNumber": 3,
  "contractAddress": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
  "cumulativeGasUsed": 314159,
  "gasUsed": 30234,
  "logs": [{
         // logs as returned by getFilterLogs, etc.
     }, ...]
}

chain3.mc.getTransactionCount

chain3.mc.getTransactionCount(addressHexString [, defaultBlock] [, callback])

Get the numbers of transactions sent from this address.

Parameters
  1. String - The address to get the numbers of transactions from.
  2. Number|String - (optional) If you pass this parameter it will not use the default block set with chain3.mc.defaultBlock.
  3. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

Number - The number of transactions sent from the given address.

Example
var number = chain3.mc.getTransactionCount("0x407d73d8a49eeb85d32cf465507dd71d507100c1");
console.log(number); // 1

chain3.mc.sendTransaction

chain3.mc.sendTransaction(transactionObject [, callback])

Sends a transaction to the network.

Parameters
  1. Object - The transaction object to send:
  • from: String - The address for the sending account. Uses the chain3.mc.defaultAccount property, if not specified.
  • to: String - (optional) The destination address of the message, can be an account address or a contract address, left undefined for a contract-creation transaction.
  • value: Number|String|BigNumber - (optional) The value transferred for the transaction in Sha, also the endowment if it’s a contract-creation transaction.
  • gas: Number|String|BigNumber - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded).
  • gasPrice: Number|String|BigNumber - (optional, default: To-Be-Determined) The price of gas for this transaction in sha, defaults to the mean network gas price.
  • data: String - (optional) Either a byte string containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code.
  • nonce: Number - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
  • shardingFlag: Number|String - (optional) Set to 1 for micro/subchain direct contract-call, 0 or undefine for global contract-creation transaction.
  1. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

String - The 32 Bytes transaction hash as HEX string.

If the transaction was a contract creation use chain3.mc.getTransactionReceipt() to get the contract address, after the transaction was mined.

Example
// compiled solidity source code using https://chriseth.github.io/cpp-ethereum/
var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b600760043502
8060005260206000f3";

chain3.mc.sendTransaction({data: code}, function(err, address) {
  if (!err)
    console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385"
});

chain3.mc.call

chain3.mc.call(callObject [, defaultBlock] [, callback])

Executes a message call transaction, which is directly executed in the VM of the node, but never mined into the blockchain.

Parameters
  1. Object - A transaction object see chain3.mc.sendTransaction, with the difference that for calls the from property is optional as well.
  2. Number|String - (optional) If you pass this parameter it will not use the default block set with chain3.mc.defaultBlock.
  3. Function - (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Returns

String - The returned data of the call, e.g. a codes functions return value.

Example
var result = chain3.mc.call({
    to: "0xc4abd0339eb8d57087278718986382264244252f",
    data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003"
});
console.log(result); // "0x0000000000000000000000000000000000000000000000000000000000000015"

chain3.mc.estimateGas

chain3.mc.estimateGas(callObject [, defaultBlock] [, callback])

Executes a message call or transaction, which is directly executed in the VM of the node, but never mined into the blockchain and returns the amount of the gas used.

Parameters

See chain3.mc.sendTransaction, expect that all properties are optional.

Returns

Number - the used gas for the simulated call/transaction.

Example
var result = chain3.mc.estimateGas({
    to: "0xc4abd0339eb8d57087278718986382264244252f",
    data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003"
});
console.log(result); // "1465"

chain3.mc.filter

// can be 'latest' or 'pending'
var filter = chain3.mc.filter(filterString);
// OR object are log filter options
var filter = chain3.mc.filter(options);

// watch for changes
filter.watch(function(error, result){
  if (!error)
    console.log(result);
});

// Additionally you can start watching right away, by passing a callback:
chain3.mc.filter(options, function(error, result){
  if (!error)
    console.log(result);
});
Parameters
  1. String|Object - The string "latest" or "pending" to watch for changes in the latest block or pending transactions respectively. Or a filter options object as follows:
  • fromBlock: Number|String - The number of the earliest block (latest may be given to mean the most recent and pending currently mining, block). By default latest.
  • toBlock: Number|String - The number of the latest block (latest may be given to mean the most recent and pending currently mining, block). By default latest.
  • address: String - An address or a list of addresses to only get logs from particular account(s).
  • topics: Array of Strings - An array of values which must each appear in the log entries. The order is important, if you want to leave topics out use null, e.g. [null, '0x00...']. You can also pass another array for each topic with options for that topic e.g. [null, ['option1', 'option2']]
Returns

Object - A filter object with the following methods:

  • filter.get(callback): Returns all of the log entries that fit the filter.
  • filter.watch(callback): Watches for state changes that fit the filter and calls the callback. See this note for details.
  • filter.stopWatching(): Stops the watch and uninstalls the filter in the node. Should always be called once it is done.
Watch callback return value
  • String - When using the "latest" parameter, it returns the block hash of the last incoming block.
  • String - When using the "pending" parameter, it returns a transaction hash of the last add pending transaction.
  • Object - When using manual filter options, it returns a log object as follows:
    • logIndex: Number - integer of the log index position in the block. null when its pending log.
    • transactionIndex: Number - integer of the transactions index position log was created from. null when its pending log.
    • transactionHash: String, 32 Bytes - hash of the transactions this log was created from. null when its pending log.
    • blockHash: String, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log.
    • blockNumber: Number - the block number where this log was in. null when its pending. null when its pending log.
    • address: String, 32 Bytes - address from which this log originated.
    • data: String - contains one or more 32 Bytes non-indexed arguments of the log.
    • topics: Array of Strings - Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.)

Note For event filter return values see Contract Events

Example
var filter = chain3.mc.filter('pending');

filter.watch(function (error, log) {
  console.log(log); //  {"address":"0x0000000000000000000000000000000000000000", "data":"0x0000000000000000000000000000000000000000000000000000000000000000", ...}
});

// get all past logs again.
var myResults = filter.get(function(error, logs){ ... });

...

// stops and uninstalls the filter
filter.stopWatching();

chain3.mc.contract

chain3.mc.contract(abiArray)

Creates a contract object for a solidity contract, which can be used to initiate contracts on an address. You can read more about events here.

Parameters
  1. Array - ABI array with descriptions of functions and events of the contract.
Returns

Object - A contract object, which can be initiated as follows:

var MyContract = chain3.mc.contract(abiArray);

// instantiate by address
var contractInstance = MyContract.at([address]);

// deploy new contract
var contractInstance = MyContract.new([contructorParam1] [, contructorParam2], {data: '0x12345...', from: myAccount, gas: 1000000});

// Get the data to deploy the contract manually
var contractData = MyContract.new.getData([contructorParam1] [, contructorParam2], {data: '0x12345...'});
// contractData = '0x12345643213456000000000023434234'

And then you can either initiate an existing contract on an address, or deploy the contract using the compiled byte code:

// Instantiate from an existing address:
var myContractInstance = MyContract.at(myContractAddress);


// Or deploy a new contract:

// Deploy the contract asyncronous:
var myContractReturned = MyContract.new(param1, param2, {
   data: myContractCode,
   gas: 300000,
   from: mySenderAddress}, function(err, myContract){
    if(!err) {
       // NOTE: The callback will fire twice!
       // Once the contract has the transactionHash property set and once its deployed on an address.

       // e.g. check tx hash on the first call (transaction send)
       if(!myContract.address) {
           console.log(myContract.transactionHash) // The hash of the transaction, which deploys the contract

       // check address on the second call (contract deployed)
       } else {
           console.log(myContract.address) // the contract address
       }

       // Note that the returned "myContractReturned" === "myContract",
       // so the returned "myContractReturned" object will also get the address set.
    }
  });

// Deploy contract syncronous: The address will be added as soon as the contract is mined.
// Additionally you can watch the transaction by using the "transactionHash" property
var myContractInstance = MyContract.new(param1, param2, {data: myContractCode, gas: 300000, from: mySenderAddress});
myContractInstance.transactionHash // The hash of the transaction, which created the contract
myContractInstance.address // undefined at start, but will be auto-filled later

Note When you deploy a new contract, you should check for the next 12 blocks or so if the contract code is still at the address (using chain3.mc.getCode()), to make sure a fork didn’t change that.

Example
// contract abi
var abi = [{
     name: 'myConstantMethod',
     type: 'function',
     constant: true,
     inputs: [{ name: 'a', type: 'string' }],
     outputs: [{name: 'd', type: 'string' }]
}, {
     name: 'myStateChangingMethod',
     type: 'function',
     constant: false,
     inputs: [{ name: 'a', type: 'string' }, { name: 'b', type: 'int' }],
     outputs: []
}, {
     name: 'myEvent',
     type: 'event',
     inputs: [{name: 'a', type: 'int', indexed: true},{name: 'b', type: 'bool', indexed: false]
}];

// creation of contract object
var MyContract = chain3.mc.contract(abi);

// initiate contract for an address
var myContractInstance = MyContract.at('0xc4abd0339eb8d57087278718986382264244252f');

// call constant function
var result = myContractInstance.myConstantMethod('myParam');
console.log(result) // '0x25434534534'

// send a transaction to a function
myContractInstance.myStateChangingMethod('someParam1', 23, {value: 200, gas: 2000});

// short hand style
chain3.mc.contract(abi).at(address).myAwesomeMethod(...);

// create filter
var filter = myContractInstance.myEvent({a: 5}, function (error, result) {
  if (!error)
    console.log(result);
    /*
    {
        address: '0x8718986382264244252fc4abd0339eb8d5708727',
        topics: "0x12345678901234567890123456789012", "0x0000000000000000000000000000000000000000000000000000000000000005",
        data: "0x0000000000000000000000000000000000000000000000000000000000000001",
        ...
    }
    */
});

Contract Methods
// Automatically determines the use of call or sendTransaction based on the method type
myContractInstance.myMethod(param1 [, param2, ...] [, transactionObject] [, callback]);

// Explicitly calling this method
myContractInstance.myMethod.call(param1 [, param2, ...] [, transactionObject] [, callback]);

// Explicitly sending a transaction to this method
myContractInstance.myMethod.sendTransaction(param1 [, param2, ...] [, transactionObject] [, callback]);

// Explicitly sending a transaction to this method
myContractInstance.myMethod.sendTransaction(param1 [, param2, ...] [, transactionObject] [, callback]);

// Get the call data, so you can call the contract through some other means
var myCallData = myContractInstance.myMethod.getData(param1 [, param2, ...]);
// myCallData = '0x45ff3ff6000000000004545345345345..'

The contract object exposes the contracts methods, which can be called using parameters and a transaction object.

Parameters
  • String|Number - (optional) Zero or more parameters of the function.
  • Object - (optional) The (previous) last parameter can be a transaction object, see chain3.mc.sendTransaction parameter 1 for more.
  • Function - (optional) If you pass a callback as the last parameter the HTTP request is made asynchronous. See this note for details.
Returns

String - If its a call the result data, if its a send transaction a created contract address, or the transaction hash, see chain3.mc.sendTransaction for details.

Example
// creation of contract object
var MyContract = chain3.mc.contract(abi);

// initiate contract for an address
var myContractInstance = MyContract.at('0x78e97bcc5b5dd9ed228fed7a4887c0d7287344a9');

var result = myContractInstance.myConstantMethod('myParam');
console.log(result) // '0x25434534534'

myContractInstance.myStateChangingMethod('someParam1', 23, {value: 200, gas: 2000}, function(err, result){ ... });

Contract Events
var event = myContractInstance.MyEvent({valueA: 23} [, additionalFilterObject])

// watch for changes
event.watch(function(error, result){
  if (!error)
    console.log(result);
});

// Or pass a callback to start watching immediately
var event = myContractInstance.MyEvent([{valueA: 23}] [, additionalFilterObject] , function(error, result){
  if (!error)
    console.log(result);
});

You can use events like filters and they have the same methods, but you pass different objects to create the event filter.

Parameters
  1. Object - Indexed return values you want to filter the logs by, e.g. {'valueA': 1, 'valueB': [myFirstAddress, mySecondAddress]}. By default all filter values are set to null. It means, that they will match any event of given type sent from this contract.
  2. Object - Additional filter options, see filters parameter 1 for more. By default filterObject has field ‘address’ set to address of the contract. Also first topic is the signature of event.
  3. Function - (optional) If you pass a callback as the last parameter it will immediately start watching and you don’t need to call myEvent.watch(function(){}). See this note for details.
Callback return

Object - An event object as follows:

  • args: Object - The arguments coming from the event.
  • event: String - The event name.
  • logIndex: Number - integer of the log index position in the block.
  • transactionIndex: Number - integer of the transactions index position log was created from.
  • transactionHash: String, 32 Bytes - hash of the transactions this log was created from.
  • address: String, 32 Bytes - address from which this log originated.
  • blockHash: String, 32 Bytes - hash of the block where this log was in. null when its pending.
  • blockNumber: Number - the block number where this log was in. null when its pending.
Example
var MyContract = chain3.mc.contract(abi);
var myContractInstance = MyContract.at('0x78e97bcc5b5dd9ed228fed7a4887c0d7287344a9');

// watch for an event with {some: 'args'}
var myEvent = myContractInstance.MyEvent({some: 'args'}, {fromBlock: 0, toBlock: 'latest'});
myEvent.watch(function(error, result){
   ...
});

// would get all past logs again.
var myResults = myEvent.get(function(error, logs){ ... });

...

// would stop and uninstall the filter
myEvent.stopWatching();

Contract allEvents
var events = myContractInstance.allEvents([additionalFilterObject]);

// watch for changes
events.watch(function(error, event){
  if (!error)
    console.log(event);
});

// Or pass a callback to start watching immediately
var events = myContractInstance.allEvents([additionalFilterObject,] function(error, log){
  if (!error)
    console.log(log);
});

Will call the callback for all events which are created by this contract.

Parameters
  1. Object - Additional filter options, see filters parameter 1 for more. By default filterObject has field ‘address’ set to address of the contract. Also first topic is the signature of event.
  2. Function - (optional) If you pass a callback as the last parameter it will immediately start watching and you don’t need to call myEvent.watch(function(){}). See this note for details.
Callback return

Object - See Contract Events for more.

Example
var MyContract = chain3.mc.contract(abi);
var myContractInstance = MyContract.at('0x78e97bcc5b5dd9ed228fed7a4887c0d7287344a9');

// watch for an event with {some: 'args'}
var events = myContractInstance.allEvents({fromBlock: 0, toBlock: 'latest'});
events.watch(function(error, result){
   ...
});

// would get all past logs again.
events.get(function(error, logs){ ... });

...

// would stop and uninstall the filter
myEvent.stopWatching();

chain3.encodeParams

chain3.encodeParams

Encode a list of parameters array into HEX codes. ##### Parameters

  • types - list of types of params
  • params - list of values of params
Example
var types = ['int','string'];
var args = [100, '4000'];

var dataHex = '0x' + chain3.encodeParams(types, args);
console.log("encoded params:", dataHex);

// outputs
encoded params:0x0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000043430303000000000000000000000000000000000000000000000000000000000

chain3.mc.namereg

chain3.mc.namereg

Returns GlobalRegistrar object.

Usage

see namereg example


chain3.mc.sendIBANTransaction

var txHash = chain3.mc.sendIBANTransaction('0x00c5496aee77c1ba1f0854206a26dda82a81d6d8', 'XE66MOACXREGGAVOFYORK', 0x100);

Sends IBAN transaction from user account to destination IBAN address.

Parameters
  • string - address from which we want to send transaction
  • string - IBAN address to which we want to send transaction
  • value - value that we want to send in IBAN transaction

chain3.mc.iban

var i = new chain3.mc.iban("XE81ETHXREGGAVOFYORK");

chain3.mc.iban.fromAddress

var i = chain3.mc.iban.fromAddress('0xd814f2ac2c4ca49b33066582e4e97ebae02f2ab9');
console.log(i.toString()); // 'XE72P8O19KRSWXUGDY294PZ66T4ZGF89INT

chain3.mc.iban.fromBban

var i = chain3.mc.iban.fromBban('XE66MOACXREGGAVOFYORK');
console.log(i.toString()); // "XE71XE66MOACXREGGAVOFYORK"

chain3.mc.iban.createIndirect

var i = chain3.mc.iban.createIndirect({
  institution: "XREG",
  identifier: "GAVOFYORK"
});
console.log(i.toString()); // "XE66MOACXREGGAVOFYORK"

chain3.mc.iban.isValid

var valid = chain3.mc.iban.isValid("XE66MOACXREGGAVOFYORK");
console.log(valid); // true

var valid2 = chain3.mc.iban.isValid("XE76MOACXREGGAVOFYORK");
console.log(valid2); // false, cause checksum is incorrect

var i = new chain3.mc.iban("XE66MOACXREGGAVOFYORK");
var valid3 = i.isValid();
console.log(valid3); // true

chain3.mc.iban.isDirect

var i = new chain3.mc.iban("XE66MOACXREGGAVOFYORK");
var direct = i.isDirect();
console.log(direct); // false

chain3.mc.iban.isIndirect

var i = new chain3.mc.iban("XE66MOACXREGGAVOFYORK");
var indirect = i.isIndirect();
console.log(indirect); // true

chain3.mc.iban.checksum

var i = new chain3.mc.iban("XE66MOACXREGGAVOFYORK");
var checksum = i.checksum();
console.log(checksum); // "66"

chain3.mc.iban.institution

var i = new chain3.mc.iban("XE66MOACXREGGAVOFYORK");
var institution = i.institution();
console.log(institution); // 'XREG'

chain3.mc.iban.client

var i = new chain3.mc.iban("XE66MOACXREGGAVOFYORK");
var client = i.client();
console.log(client); // 'GAVOFYORK'

chain3.mc.iban.address

var i = new chain3.mc.iban('XE72P8O19KRSWXUGDY294PZ66T4ZGF89INT');
var address = i.address();
console.log(address); // 'd814f2ac2c4ca49b33066582e4e97ebae02f2ab9'

chain3.mc.iban.toString

var i = new chain3.mc.iban('XE72P8O19KRSWXUGDY294PZ66T4ZGF89INT');
console.log(i.toString()); // 'XE72P8O19KRSWXUGDY294PZ66T4ZGF89INT'

Checking the Balance of Your Account

You only need your public wallet address in order to see your balance. It is not recommended that you access your wallet by entering your private key anywhere if you just want to check the balance or see incoming or outgoing transactions. The fewer times that you need to open your wallet, the better.

MOAC mainnet http://explorer.moac.io/. Paste your address into the search bar and it will pull up your address and transaction history.

Tokens You cannot see all tokens on https://explorer.moac.io/ now. We are working on it to display registered tokens on the website.

MoacWalletOnline You can also enter your address on MoacWalletOnline View Wallet Info page by selecting the “View With Address Only” option at the bottom. Note: This only allows your to view your balances, NOT access you wallet to send funds. Remember, you must have the private key in order to access your account.

常用命令:

--testnet: connect to MOAC testnet (networkid = 101);

--rpc: 启用HTTP的RPC服务,以便非本机访问该MOAC节点服务;

--rpcaddr value: 默认是"localhost", 只能本机访问; 可通过设置 为"0.0.0.0", 以便非本机访问该MOAC节点服务, 但现在RPC服务是基于HTTP的,是明文传输,需注意安全问题;

--rpcport value: 默认是"8545",  一般来说不用改,用默认端口即可;

--rpcapi value: 指定RPC要开放的API服务,默认为"chain3,mc,net",常用的一般还会配置比如personal,admin,debug,miner,txpool,db,shh等,但是因为RPC服务是明文传输,所以,如果使用personal的时候,要注意安全问题;

--rpccorsdomain value: 一般来说,如果你知道要用这个选项的时候,使用""值即可,更详细可自行搜索“CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)”中相关关键词进一步了解;

--jspath loadScript: 默认值为".", loadScript装载javascript文件的主目录;

示例如下:

启动MOAC节点并连接到mainnet(networkid = 99)

./moac

通过本地ipc接口连接到MOAC mainnet节点,并启动命令行

./moac attach

启动MOAC节点并连接到testnet(networkid = 101)

./moac --testnet

启动MOAC测试节点,并启动交互命令行

./moac --testnet console

通过本地ipc接口连接到MOAC节点

./moac attach /xx/xxx/moac.ipc

通过基于HTTP的RPC接口连接到本地或者远程MOAC节点

./moac attach http://xxx.xxx.xxx.xxx:8545

启动MOAC测试节点,同时启动RPC服务

./moac --testnet --rpc

启动MOAC测试节点,非本机可访问,非本机也可以使用personal及debug服务,同时提供跨域资源共享服务

./moac --testnet --rpc --rpcaddr=0.0.0.0 --rpcapi="db,mc,net,chain3,personal,debug" --rpccorsdomain=""

全部命令行参数

在命令行下,输入:

$ ./moac help

或者

$ ./moac --help
moac - the MOAC-core command line interface

Copyright 2017 The MOAC Authors

USAGE:

moac [options] command [command options] [arguments...]

VERSION:

0.8.3-release-f84b7d91

account     Manage accounts
attach      Start an interactive JavaScript environment (connect to node)
bug         opens a window to report a bug on the moac repo
console     Start an interactive JavaScript environment
dump        Dump a specific block from storage
dumpconfig  Show configuration values
export      Export blockchain into file
import      Import a blockchain file
init        Bootstrap and initialize a new genesis block
js          Execute the specified JavaScript files
license     Display license information
makecache   Generate ethash verification cache (for testing)
makedag     Generate ethash mining DAG (for testing)
monitor     Monitor and visualize node metrics
removedb    Remove blockchain and state databases
version     Print version numbers
wallet      Manage MoacNode presale wallets
help, h     Shows a list of commands or help for one command
--config value                            TOML configuration file
--datadir "/Users/zpli/Library/MoacNode"  Data directory for the databases and keystore
--keystore                                Directory for the keystore (default = inside the datadir)
--nousb                                   Disables monitoring for and managing USB hardware wallets
--networkid value                         Network identifier (integer, 99=mainnet, 101=testnet, 100=devnet) (default: 99)
--testnet                                 MOAC test network: pre-configured proof-of-work test network
--dev                                     Developer mode: pre-configured private network with several debugging flags
--syncmode "fast"                         Blockchain sync mode ("fast", "full", or "light")
--mcstats value                           Reporting URL of a mcstats service (nodename:secret@host:port)
--identity value                          Custom node name
--lightserv value                         Maximum percentage of time allowed for serving LES requests (0-90) (default: 0)
--lightpeers value                        Maximum number of LES client peers (default: 20)
--lightkdf                                Reduce key-derivation RAM & CPU usage at some expense of KDF strength
--ethash.cachedir                      Directory to store the ethash verification caches (default = inside the datadir)
--ethash.cachesinmem value             Number of recent ethash caches to keep in memory (16MB each) (default: 2)
--ethash.cachesondisk value            Number of recent ethash caches to keep on disk (16MB each) (default: 3)
--ethash.dagdir "/Users/zpli/.ethash"  Directory to store the ethash mining DAGs (default = inside home folder)
--ethash.dagsinmem value               Number of recent ethash mining DAGs to keep in memory (1+GB each) (default: 1)
--ethash.dagsondisk value              Number of recent ethash mining DAGs to keep on disk (1+GB each) (default: 2)
--txpool.nolocals            Disables price exemptions for locally submitted transactions
--txpool.journal value       Disk journal for local transaction to survive node restarts (default: "transactions.rlp")
--txpool.rejournal value     Time interval to regenerate the local transaction journal (default: 1h0m0s)
--txpool.pricelimit value    Minimum gas price limit to enforce for acceptance into the pool (default: 1)
--txpool.pricebump value     Price bump percentage to replace an already existing transaction (default: 10)
--txpool.accountslots value  Minimum number of executable transaction slots guaranteed per account (default: 16)
--txpool.globalslots value   Maximum number of executable transaction slots for all accounts (default: 40960)
--txpool.accountqueue value  Maximum number of non-executable transaction slots permitted per account (default: 64)
--txpool.globalqueue value   Maximum number of non-executable transaction slots for all accounts (default: 1024)
--txpool.lifetime value      Maximum amount of time non-executable transaction are queued (default: 3h0m0s)
--cache value            Megabytes of memory allocated to internal caching (min 16MB / database forced) (default: 128)
--trie-cache-gens value  Number of trie node generations to keep in memory (default: 120)
--unlock value    Comma separated list of accounts to unlock
--password value  Password file to use for non-inteactive password input
--rpc                  Enable the HTTP-RPC server
--rpcaddr value        HTTP-RPC server listening interface (default: "localhost")
--rpcport value        HTTP-RPC server listening port (default: 8545)
--rpcapi value         API's offered over the HTTP-RPC interface
--ws                   Enable the WS-RPC server
--wsaddr value         WS-RPC server listening interface (default: "localhost")
--wsport value         WS-RPC server listening port (default: 8546)
--wsapi value          API's offered over the WS-RPC interface
--wsorigins value      Origins from which to accept websockets requests
--ipcdisable           Disable the IPC-RPC server
--ipcpath              Filename for IPC socket/pipe within the datadir (explicit paths escape it)
--rpccorsdomain value  Comma separated list of domains from which to accept cross origin requests (browser enforced)
--jspath loadScript    JavaScript root path for loadScript (default: ".")
--exec value           Execute JavaScript statement
--preload value        Comma separated list of JavaScript files to preload into the console
--bootnodes value     Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)
--bootnodesv4 value   Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)
--bootnodesv5 value   Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)
--port value          Network listening port (default: 30333)
--maxpeers value      Maximum number of network peers (network disabled if set to 0) (default: 25)
--maxpendpeers value  Maximum number of pending connection attempts (defaults used if set to 0) (default: 0)
--nat value           NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>) (default: "any")
--nodiscover          Disables the peer discovery mechanism (manual peer addition)
--v5disc              Enables the experimental RLPx V5 (Topic Discovery) mechanism
--netrestrict value   Restricts network communication to the given IP networks (CIDR masks)
--nodekey value       P2P node key file
--nodekeyhex value    P2P node key as hex (for testing)
--mine                    Enable mining
--minerthreads value      Number of CPU threads to use for mining (default: 8)
--moacbase value          Public address for block mining rewards (default = first account created) (default: "0")
--targetgaslimit value    Target gas limit sets the artificial target gas floor for the blocks to mine (default: 9000000)
 --gasprice "18000000000"  Minimal gas price to accept for mining a transactions
--extradata value         Block extra data set by the miner (default = client version)
--gpoblocks value      Number of recent blocks to check for gas prices (default: 10)
--gpopercentile value  Suggested gas price is the given percentile of a set of recent transaction gas prices (default: 50)
--vmdebug  Record information useful for VM and contract debugging
--metrics                 Enable metrics collection and reporting
--fakepow                 Disables proof-of-work verification
--nocompaction            Disables db compaction after import
--verbosity value         Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: 3)
--vmodule value           Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. mc/=5,p2p=4)
--backtrace value         Request a stack trace at a specific logging statement (e.g. "block.go:271")
--debug                   Prepends log messages with call-site location (file and line number)
--pprof                   Enable the pprof HTTP server
--pprofaddr value         pprof HTTP server listening interface (default: "127.0.0.1")
--pprofport value         pprof HTTP server listening port (default: 6060)
--memprofilerate value    Turn on memory profiling with the given rate (default: 524288)
--blockprofilerate value  Turn on block profiling with the given rate (default: 0)
--cpuprofile value        Write CPU profile to the given file
--trace value             Write execution trace to the given file
--fast      Enable fast syncing through state downloads
--light     Enable light client mode
--help, -h  show help
Copyright 2017-2018 MOAC Authors

MOAC developed based on the Ethereum project. It also implements a *javascript runtime environment* (JSRE) that can be used in either interactive (console) or non-interactive (script) mode.

MOAC Javascript console exposes the chain3 JavaScript Dapp API and the admin API.

Interactive use: the JSRE REPL Console

启动MOAC的Console常用两种方式:

  • 通过本地IPC连接

    ./moac attach /xx/xxx/xxxx.ipc
    
  • 通过HTTP的RPC连接

    ./moac attach http://xxx.xxx.xxx.xxx:xxxx
    

    常用功能如下:

  • 通过相对路径装载并运行javascript文件

    loadScript("./mctest.js")
    

// TODO 稍后更新

Background

Blockchain technology has been evolving very quickly since the introduction of Bitcoin in 2008. Over the past nine years, many Blockchain techniques have been explored to try out various ideas, in the hope to expand the Blockchain usage, performance and applications. At the same time, the token value of Blockchain plays a vital role in the adoption of the blockchains. It helps to incentive more participants to join the ecosystem, also acts extremely useful to augment the existing payment system in a more efficient way. However, as Blockchain in its still early stage, it suffers from couples of problem.

  1. Difficult to try new idea New idea means a new Blockchain. It requires extensive overhead to implement a new Blockchain idea, by setting up servers, develop teams, establishing community, attracting new users, etc.
  2. Difficult to upgrade Once Blockchain has been deployed and in production, it is very difficult to add/modify/delete features. Any of those is either soft fork or hard fork. Either fork requires tremendous effort and economic consequences.
  3. Incompatible among chains Different chains have different schemes, such as consensus protocol, currency features, and adoption requirements. These schemes prevent the interconnection or exchange among multiple chains.
  4. Split participant group For each Blockchain, the user base is different. Mining rigs and validators are dedicated for that chain only. No two blockchains can share any of them.
  5. Performance issue Blockchain as a decentralized solution, suffers performance hit compared to traditional centralized solution, such as throughput, respond time, etc. It is very difficult to improve performance and still maintain distributed Byzantine Fault Tolerant.

Also, as most cryptocurrencies’ value increases dramatically in the last year, applications based on existing blockchain platforms suffer from higher fees and longer latencies. ### MOAC solution Over the past several years, multiple consensus protocols have been adopted and tried out including POW, POS, BFT, and hybrid of those. However, not a single protocol can solve all problems. Typically, POW can be deployed in a large scale network and scales very well. It is the most verified consensus protocol among all. But it suffers from problems like large power consumption, low throughput, high latency, and higher barrier to participate. POS (DPOS) is better on power consumption and could be configured to perform faster. However, the protocol is complex to implement, and economical consequence has not been fully tested in large scale. And it typically deploys in a smaller network scale. BFT family is normally used in a much smaller scenario and can perform much better in term of throughput and latency. So its usage is mostly focused on private chain or enterprise applications.

To be able to deploy in a large network scale and benefit from more participants and decentralization, while keeping the high throughput and low latency, MOAC introduces the layered consensus stacks to make above goals practical. It is the Blockchain for blockchains. MOAC itself will be deployed in public network with large number of validators. It provides following:

  1. Layered configuration structure
  2. Transaction, Smart Contract and Data Access support
  3. Data flow, control flow and processing units, to form a distributed Von Neumann architecture.
  4. Validators could be configured to support multiple overlapping sub blockchains.
  5. Pluggable validation scheme to support injection of user defined protocols, make it easy to deploy new sub blockchains using existing validators.
  6. Encourage user with smaller processing power to participate in the validation process.
  7. Sharding solution to improve performance dramatically.

Consensus Protocol

We realize simply extend any current consensus protocol won’t be able to meet all the requirements. Typical solution of combining two types of different consensus protocols results in multiple chains or side chains. This is the approach we want to avoid, as it introduces more problems than solve them. Our solution to the consensus dilemma is to build a layered consensus stack, but to keep everything synced in a single Blockchain. For the underlying layer, we utilize POW as the main consensus protocol, because POW is a widely tested protocol and most robust solution to a large scale network setup. Currently MOAC uses POW similar to Ethereum.

The drawback of POW is compensated in the top layer. Only critical transactions and control flow transactions are processed in the POW layer. The top layer adopts POS consensus protocol with sharding technique to provide faster and higher throughput solution. Each POW node has one Smart Contract Server node. The Smart Contract Server (SCS) identity is fully verifiable by the corresponding POW node. Each SCS node will present holding stake to be able to process the top layer user requests.

Note that SCS processes Smart Contract calls. All transaction in the top layer is in form of Smart Contract calls. Not all SCS will process single transaction at the same time. Rather, part of selected SCS will process specific transaction. The selection of SCS is through initialization of Smart Contract call or Flush call. The init/flush call is actually passed to the POW and achieves consensus in underlying layer. The init/flush call will include the selection criteria including percentage of processing nodes. Then each POW will invoke that call on its SCS with an EHDRand algorithm. SCS will determine if itself is selected to process this Smart Contract. Note this is a deterministic process and SCS participation can be verified by anyone.

Once group of SCS is selected for certain Smart Contract, they will communicate with each other to form a small consensus group. This group will process the following Smart Contract calls on that Smart Contract. Also, the behavior on how they reach the consensus among them could be specified by the init/flush call. Effectively these SCS nodes form a sub Blockchain and perform the consensus based on the predefined protocol or user defined protocol. Please note the consensus protocol is different from the actual Smart Contract code. Smart Contract state is saved in each SCS. However, that is not on the actual global Blockchain. To achieve the benefit of global Blockchain, the state needs to flush into the underlying Blockchain periodically or on demand.

When flushing, in the consensus mode, SCS node will initiate a data store request on the underlying POW nodes. The current state will be written into the Blockchain and referenceable by a HASH. Note all POW node will do the same operation. For those nodes who are not part of the consensus group, they will not do anything. The participating SCS will get the proposed state and verify it with its own state. If it can prove that the proposed state is incorrect, it will initiate another data store request with corrected state and referencing the incorrect state hash. If no rebuttal data store request is initiated for predefined rounds, SCS node will initiate the final flush Smart Contract call with the correct state hash. The involved transactions in the correct state will be processed at every POW node. The SCS node who sends out the incorrect state will forfeit its stake.

In MOAC, most transactions will be processed in the top layer, while only small portion of control flow transactions are processed in the POW layer. This is feasible because top layer provides fast, flexible and low cost service, while POW layer provides slow, reliant and expensive service.

Layered Architecture

  1. P2P network layer. This layer defines p2p protocol.
  2. Blockchain layer. This layer handle all operation related to Blockchain operation, like consensus, data access, etc.
  3. TX layer. This layer handles TX request and reply. It also processes the Control flow TX request and if necessary, invokes Smart Contract related operations.
  4. Smart Contract layer. This layer performs smart contract execution inside virtual machine and also keeps a temporary contract state.
  5. API handles end-user input and gets the output from lower layers.

MOAC topology

The POW consensus node participates in a volunteer way. Each node contributes its computing power to solve the computation-intensive problem and verifies the validity of transactions in the agreed transaction set. Besides the POW consensus on transaction and data store set, each POW node is associated with one Smart Contract Server. SCS node could be local to the POW node, or it could be a remote node. The Smart Contract Server (SCS) identity is fully verifiable by the corresponding POW node.

Smart contract request (create/invoke/flush) is enclosed in the Control flow TXc and is first processed in underlying layer. Then, each POW node sends the contract request to its SCS via an asynchronous call. SCS will send additional Control flow TXc and Data Store TXs to underlying layer if needed.

Execution of smart contract is in an efficient sharded way. All the SCS can be configured at run time to process different sections of smart contracts. The whole system throughput could be 10x-100x faster than that of traditional way. The sharded execution group marshals the sharding state into underlying Blockchain through Control flow TXc and Data Store TXs.

Wallet/Address

Wallet and address are interchangeable in this document. Address holds the balance of the digital currency. Each address has its corresponding secret key. Secret key is used to sign the TX originated by this address.

Smart Contract

Identification for smart contract is same as normal wallet. It has a unique public address. One difference is that contract secret key is discarded at creation. So no one can distribute the balance of a contract to anyone else, other than the consensus protocol. Contract holds four basic elements: {code, state, [call], balance}. Code is generated by user. State holds current internal information. Balance is the digital currency the contract has. It also stores history of function calls on that contract.

Transaction

Transaction is the basic operation inside the system. Each address can send/receive balance to/from other addresses. And there are also Smart Contract based TXs. These TXs are used to trigger the work flow of Smart Contract. Three basic transaction types in the system: Payment Transaction TXp, Data Store TXs, Control flow TXc. They are processed in the underlying POW consensus nodes. All nodes agree on the same world state.

  1. Payment TX: {sender->receiver:amount} Basic transaction to move fund from one to another. Sender will need to sign the transaction using secret key. The signature is verifiable by anyone.
  2. Data store TX {sender->contract_address: data to store} This transaction type processed in POW node will not validate any balance related operation.
  3. Control flow TX
  1. Contract init TX {code, sender, init_amount, execution type, sharding config, via address}User sends the init TX to start a new contract. In the contract, user will need to specify the contract code, init fund, execution type: fast or normal, sharding config.
  2. Contract Flush TX {contract_address, flush_target_state, flush_steps} Flush TX is to allow POW node agree on the already executed bulk transactions and flush them into the Blockchain.
  3. Contract Payment TX {sender->contract_address: amount} This is similar to normal payment TX, except that POW node will notify contract server about the balance update and who made the contribution.

Sub Blockchain

MOAC system can perform regular payment transactions, data store transactions and Smart Contract (control flow) transactions. Moreover, it is very convenient to utilize the provided architecture to spawn sub blockchains. User can configure sub chain using Smart Contract to define sub chain properties (% of participant nodes, consensus protocol, policy, state storage, etc.). The creation of sub chain is accomplished through Control flow TXc. Once sub chain is established, each participant SCS will adopt the pluggable protocol in its execution. Any following requests on the sub chain will be validated by the selected % of SCS. The block generation of the sub chain is configured to either on-demand or on set time schedule. The on-demand feature is preferred, as it only generate blocks when needed, thus saving valuable resources. The sub chain deployment can be as easy as sending couples of Smart Contract calls. However, it inherits the secure and robust underlying Blockchain properties. And, it can reuse the large pool of existing validators and benefit from the decentralized setup. The sub chain could utilize Flush contract call to randomly reselect SCS nodes, to achieve better decentralization and security. Upgrade sub chain is also easy by just redeploying to a new set of SCS with updated chain property.

Transaction Fee

There are two types of compensation payments that nodes can receive from contributing their computational power. Firstly, the POW nodes will get rewarded for each block they mine. This is similar to what currently BITCOIN does. Secondly, the SCS server can be rewarded for their participation of sub chains and their processing work of Smart contracts. Note that this kind of service may not be power-intensive. For example, if a sub chain is based on POS, the SCS can just spend very limited resource for the validation. This is a big incentive to regular PC users or even mobile users. For the pure POW network, there is almost no chance for regular user to benefit from mining. However, in MOAC setup, user can setup a light weight POW node. Although this light weight POW node has almost no chance to win in mining contest, but, he/she can setup an SCS associated with that POW node, and gets rewarded for the SCS works it provides. This will encourage more users to join the consensus system and provide more SCS processing power. On the other hand, the Smart Contract owner or sub chain creator will need to pay the fee for all SCS working, but is very cost-effective considering the benefit and low startup costs. The whole process will promote a more distributed ecosystem and benefit all parties.

Payment schedule

Block is mined every 10s, with reward of 2 MOAC coins per block.

The reward schedule halves every 12,500,000 blocks, equivalent to approx. four years.

After block 15,000,000, the reward will be constant of 0.1 MOAC per block. See below.

We define 1 MOAC = 1,000,000 Sand. 1 Sand = 1,000 Xiao.

Block# Reward (1 MOAC = 1,000,000 Sand)
1-12,500,000 2 MOAC
12,500,001 - 25,000,000 1 MOAC
25,000,000 - 37,500,000 0.5 MOAC
37,500,001 - 50,00,000 0.25 MOAC
50,000,001 - 62,500,000 0.125 MOAC
> 62,500,001 0.1 MOAC

Transaction fee is paid in two ways. One is through Transaction. The other is for Smart Contract or sub chain. Smart Contract Call cost is set lower than underlying transaction in purpose, thus encouraging the usage of SCS. This can alleviate the pressure on the underlying layer, and also benefit the SCS providers.

Summary

To summarize, MOAC utilizes layered architecture to combine the POW feature of robust and scalability and the POS feature of fast performance, quick response, without their shortcomings. The Smart Contract layer forms a platform for complex task and various sub blockchains. The POW nodes together with SCS nodes, construct the flexible and scalable framework that can be reused across many applications. MOAC Blockchain could be valuable to both light weight participants and compute intensive participants.

What are the different types of private key formats that I can use to access my wallet?

The MOAC is stored on the blockchain, your MOAC private key or Keystore File or whatever piece of information you have proves ownership of that MOAC, which allows you to move it.

At the end of the day, you are always signing with your private key.

However, for additional functionality (like protecting it with a password) there are formats & ways of storing your private key:

Keystore File (UTC / JSON)

  • This is encrypted by the password you chose.
  • This is the recommended version to save.
  • This Keystore file matches the format used by Mist so you can easily import it in the future.
  • Make sure to have multiple backups.
SaveKeystore

SaveKeystore

Private Key (unencrypted)

  • This is the unencrypted text version of your private key, meaning no password is necessary.
  • If someone were to find your unencrypted private key, they could access your wallet without a password.
  • For this reason, encrypted versions are typically recommended. To learn about how you can encrypt your private key, click here for more information.
  • However, you should print the paper wallet or save this in an offline environment (like a piece of paper or USB drive). This ensures a lost password does not result in lost MOAC, and acts as another backup.
PrivatekeyHide

PrivatekeyHide

You can check the actual conent of the private key but be sure not to discolose to anybody suspicious.

Privatekey

Privatekey

MetaMask

You can use Metamask to save your keypairs but currently MetaMask do not support MOAC transaction yet.

Ledger or TREZOR or Digital Bitbox Hardware Wallets

You can use TREZOR or Digital Bitbox Hardware Wallets to store the MOAC keypairs but they do not support MOAC transaction yet.

Creating your own ERC20 Token on the MOAC blockchain

Before you read this page, you should:

  • Understand the following general concepts: blockchain, smart contracts, ERC20 tokens;
  • Be able to write a basic Ethereum smart contract in Solidity (see tutorial example);

After you read this page, you will be able to:

  • Write your own ERC20 token contract;
  • Compile and deploy it on the MOAC blockchain;
  • Use the ERC20 token;

Write the ERC20 token smart contract

The ERC20 standard is developed by the Ethereum community.

contract ERC20Token {
  string  public name;
  string  public symbol;
  uint    public decimals;
  uint256 public totalSupply;

  function balanceOf(address _owner) public constant returns (uint256 balance);
  function transfer(address _to, uint256 _value) public returns (bool success);
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
  function approve(address _spender, uint256 _value) public returns (bool success);
  function allowance(address _owner, address _spender) public constant returns (uint256 remaining);
  event Transfer(address indexed _from, address indexed _to, uint256 _value);
  event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

User can develop its own ERC20 token. For that, we can either use a ready open source library to help with the task, or write the needed smart contracts directly from scratch. We will show both methods below so you can master your ERC20 token development skills.

Using a ready open source library

Let’s see how you can implement this interface by taking advantage of the OpenZeppelin Solidity library, for instance. We will write a TestCoin based on, for example, the PausableToken contract in OpenZeppelin:

pragma solidity ^0.4.18;

import "zeppelin-solidity/contracts/token/PausableToken.sol";

contract TestCoin is PausableToken {
  string public name = "Test";
  string public symbol = "TEST";
  uint public decimals = 6;
  uint public INITIAL_SUPPLY = 100000000 * (10 ** decimals);

  function TestCoin() public {
    totalSupply = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }
}

To understand better all the steps that the inheritance from PausableToken has achieved in making our TestCoin a useful ERC20-compliant token (and why it can be helpful to start from an open source library like OpenZeppelin), you can follow closely the code of each of the library’s files that were imported after each inheritance and import is fully expanded.

For that, browsing the OpenZeppelin ERC20 token github repo will be very helpful: our TestCoin is inheriting from PausableToken, which itself inherits from StandardToken, which inherits from BasicToken and ERC20, and so on all the way to ERC20Basic and the SafeMath library import.

Developing your smart contract directly

Another way of doing this is to simply write the ERC20 interface and your contract implementing it directly from scratch. As you’ll see, this is actually a fairly straightforward task:

pragma solidity ^0.4.16;

contract ERC20Token {
  uint256 public totalSupply;

  function balanceOf(address _owner) public constant returns (uint256 balance);
  function transfer(address _to, uint256 _value) public returns (bool success);
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);

  function approve(address _spender, uint256 _value) public returns (bool success);

  function allowance(address _owner, address _spender) public constant returns (uint256 remaining);

  event Transfer(address indexed _from, address indexed _to, uint256 _value);
  event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

contract TestToken is ERC20Token {

  string  public name = "Test Coin";
  string  public symbol = "TEST";
  uint8   public decimals = 6;
  uint256 public INITIAL_SUPPLY = 100000000 * (10 ** uint256(decimals));

  mapping (address => uint256) balances;
  mapping (address => mapping (address => uint256)) allowed;

  function TestToken() {
    totalSupply = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }

  function transfer(address _to, uint256 _value) public returns (bool success) {
    require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
    require(_to != 0x0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
    balances[_to] += _value;
    balances[_from] -= _value;
    allowed[_from][msg.sender] -= _value;
    emit Transfer(_from, _to, _value);
    return true;
  }

  function balanceOf(address _owner) public constant returns (uint256 balance) {
    return balances[_owner];
  }

  function approve(address _spender, uint256 _value) public returns (bool success) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }
}

Make sure to save your TestToken contract to a file on your computer (e.g. TestToken.sol).

Compile and deploy ERC20 token smart contract

As a next step, you’ll need to generate the bytecode and ABI for your new smart contract. You can think of the bytecode as basically your contract’s compiled code. The ABI (Application Binary Interface) is a JavaScript Object that defines how to interact with your smart contract.

We will show three ways of achieving this as well - using MOAC wallet, Remix web IDE for Solidity development, or compiling using the solc compiler on your machine (i.e. the command line).

Using MOAC wallet

MOAC wallet is an online free, client-side interface for using MOAC wallets, make transactions and deploy contract. It was developed based on open-source software. To use the service, you need to run a local MOAC node with addition command line arguments:

--rpccorsdomain "http://wallet.moac.io"

This will allow the access of MOAC node using MOAC wallet.

Otherwise you will see the following error message:

ERC20\_moacwallet01.png

ERC20_moacwallet01.png

Example command to start a MOAC node connecting with mainnet:

moac --rpccorsdomain "http://wallet.moac.io" --rpc --rpcport "8545" --rpcapi "chain3,mc,net,db"

A successful interface connecting to mainnet looks like this:

ERC20\_moacwallet02.png

ERC20_moacwallet02.png

To compile the contract, click the “CONTRACTS” icon:

ERC20\_moacwallet03.png

ERC20_moacwallet03.png

Then enter the contract deploy page:

ERC20\_moacwallet04.png

ERC20_moacwallet04.png

Copy the source code and paste in the “SOLIDITY CONTRACT SOURCE CODE” section. After copying the source code, the compiling process will automatically started. If no errors are not found, the right side should show a “SELECT CONTRACT TO DEPLOY” menu.

ERC20\_moacwallet05.png

ERC20_moacwallet05.png

Select the contract name “TokenERC20”:

ERC20\_moacwallet06.png

ERC20_moacwallet06.png

Input the parameters values from the menu:

ERC20\_moacwallet07.png

ERC20_moacwallet07.png

You need to have enough balance to deploy the contract. You can choose the amount of fee to use when deploying the contract. Click the DEPLOY button:

ERC20\_moacwallet08.png

ERC20_moacwallet08.png

This is the contract ready to send from Account 1. The Provide gas is estimated by the compiler and we suggest you use it or put a larger number. If gas is not enough, the contract cannot be created. To continue, be sure to unlock the account to create the contract. You can use a console attached to the MOAC to do this:

ERC20\_moacwallet09.png

ERC20_moacwallet09.png

After deploying, the interface is returned to the main menu and you can see the following transaction is creating.

ERC20\_moacwallet10.png

ERC20_moacwallet10.png

After 12 confirmations, you can start using the contract by click the admin page link.

ERC20\_moacwallet11.png

ERC20_moacwallet11.png

MOAC wallet is good for beginners that only need basic contract development needs. It cannot debug contracts. To advanced developers, you can use Remix to work with contracts.

Remix

Remix is an online tool developed by Ethereum community to work with smart contracts. MOAC also supports the deploy of smart contract through Remix.

Open Remix on your browser, create a new file called ‘TestToken.sol’ and copy paste the code of your smart contract. Make sure you are including all the other Solidity files that your code is referencing with imports, especially if you are using the open source library approach.

Select ‘TestToken’ in the Compile window then click “Start to Compile” and the Details button next to TestToken. Upon scrolling in the popup details window for TestToken, you should be able to see similar sections to this Remix screenshot for the bytecode and ABI of your smart contract:

If the contract is compiled successfully, remix will show the interface like this:

ERC20\_moacwallet12.png

ERC20_moacwallet12.png

To deploy the contract, you need to connect REMIX to a local or remote MOAC node. In addition to other arguments, be sure to enable the access of REMIX to the MOAC node with

moac --rpccorsdomain "http://remix.ethereum.org" --rpc --rpcport "8545" --rpcapi "chain3,mc,net,db"

Click the Run Tab and you should see the following menu:

ERC20\_moacwallet13.png

ERC20_moacwallet13.png

Choose the Environment menu: JavaScript VM is a simulated environment of Remix, it can be use to debugging the contract without actually deploying the contract to a real network. Injected Web3 is the default web3 connecting to Ethereum network. To deploy MOAC contract, you need to choose Web3 Provider.

ERC20\_moacwallet14.png

ERC20_moacwallet14.png

After choose “Web3 Provider”, you can see a message like this:

Click “OK”,

ERC20\_moacwallet15.png

ERC20_moacwallet15.png

You need to make sure the port is the same as the local running node.

ERC20\_moacwallet12.png

ERC20_moacwallet12.png

You may see the error message like this:

ERC20\_moacwallet17.png

ERC20_moacwallet17.png

If you see this error message, check the local node that include both

--rpccorsdomain "http://remix.ethereum.org"

and

--rpcport "8545"

If the connection is established, you should see your accounts from the Account List.

ERC20\_moacwallet18.png

ERC20_moacwallet18.png

Before you deploy the contract, you need to unlock the account that send the contract. You can do the unlock with the MOAC console:

ERC20\_moacwallet09.png

ERC20_moacwallet09.png

After successfully deployed the contract, you should see the contract address and other information showed in the menu:

ERC20\_moacwallet19.png

ERC20_moacwallet19.png

Remix is good for developing and debugging smart contracts. It is not very convenient to deploy multiple contracts. If your requires to deploy multiple contracts, you can use the Node.Js packages.

Using the Node.Js packages

You need to install solc package to compile the smart contract, and chain3 package to deploy the contract.

To use the latest stable version of the Solidity compiler via Node.js you can install it via npm:

npm install solc
var solc = require('solc')
var input = 'contract x { function g() {} }'
// Setting 1 as second paramateractivates the optimiser
var output = solc.compile(input, 1)
for (var contractName in output.contracts) {
        // code and ABI that are needed by web3
        console.log(contractName + ': ' + output.contracts[contractName].bytecode)
        console.log(contractName + '; ' + JSON.parse(output.contracts[contractName].interface))
}

To deploy the contracts, you need to install the Chain3 package:

npm install chain3

There is an example file in the package: example/contract_deploy.js

After successfully deploy, you should see the contract is displayed

Succeed!: 0x95d703ea48477f48335ae9c477ce6d986bc68453dfe3d6582714045456b93405

Using solc compiler to generate the ABI and bytecode Another way of generating these two files is to compile your smart contract using the solc compiler on your machine. If you haven’t used solc yet, you can follow these instructions for installing it on your machine.

Open a Terminal window and navigate to your working directory where you have saved your TestToken.sol file. Run the following command to export the ‘TestToken.abi’ and ‘TestToken.bin’ files to the bin directory:

solc --bin --abi -o bin TestToken.sol

As the file extensions suggest, ‘TestToken.abi’ contains your contract’s ABI, and ‘TestToken.bin’ contains its bytecode.

If you prefer accessing the solc compiler from within a program’s code to generate the ABI and bytecode files rather than using the command line, you can use the following code instead:

var fs =  require ( ' fs ' );
var solc =  requires ( 'solc' );

var cmds = process.argv;
if(cmds != null && cmds.length > 2){
  var file = cmds[2];
  var name = cmds[3];
  var content = fs.readFileSync(file).toString();

  was input = {
    file: content
  };

  var output = solc.compile({sources: input}, 1);
  console.log('contracts', Object.keys(output.contracts));

  var ctt = output.contracts[name];
  if(ctt == null){
      return;
  }

  var bytecode = ctt.bytecode;
  var abi = JSON.parse(ctt.interface);

  console.log('bytecode', bytecode);
  console.log('abi', ctt.interface);
}

Regardless of which method you followed, you should now have the ABI and bytecode files for your TestToken smart contract. Next, you will be able to deploy your token contract on the MOAC blockchain for others to interact with it.

Creating your own ERC721 Token on MOAC blockchain

Before you read this page, you should:

  • Understand the following general concepts: blockchain, smart contracts, ERC721 tokens;
  • Be able to write a basic Ethereum smart contract in Solidity (see tutorial example);

After you read this page, you will be able to:

  • Write your own ERC721 token contract;
  • Compile and deploy it on the MOAC blockchain;
  • Use the ERC721 token;

Write the ERC721 token smart contract

The ERC721 standard is developed by the Ethereum community. It is a standard interface for non-fungible tokens(NFT), also known as deeds.

contract ERC721 {
    function balanceOf(address _owner) external view returns (uint256);
    function ownerOf(uint256 _tokenId) external view returns (address);
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function approve(address _approved, uint256 _tokenId) external payable;
    function setApprovalForAll(address _operator, bool _approved) external;
    function getApproved(uint256 _tokenId) external view returns (address);
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
    event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
}

User can develop its own ERC721 token. For that, we can either use a ready open source library to help with the task, or write the needed smart contracts directly from scratch. We will show all three methods below so you can master your ERC721 token development skills.

Using a ready open source library

Let’s see how you can implement this interface by taking advantage of the OpenZeppelin Solidity library, for instance. We will write a TestCoin based on, for example, the PausableToken contract in OpenZeppelin:

pragma solidity ^0.4.18;

import "./ERC721Basic.sol";
import "./ERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../AddressUtils.sol";

contract ERC721BasicToken is ERC721Basic {
  using SafeMath for uint256;
  using AddressUtils for address;

  // Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
  // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
  bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;

  // Mapping from token ID to owner
  mapping (uint256 => address) internal tokenOwner;

  // Mapping from token ID to approved address
  mapping (uint256 => address) internal tokenApprovals;

  // Mapping from owner to number of owned token
  mapping (address => uint256) internal ownedTokensCount;

  // Mapping from owner to operator approvals
  mapping (address => mapping (address => bool)) internal operatorApprovals;

  modifier onlyOwnerOf(uint256 _tokenId) {
    require(ownerOf(_tokenId) == msg.sender);
    _;
      }

modifier canTransfer(uint256 _tokenId) {
require(isApprovedOrOwner(msg.sender, _tokenId));
_;
}

function balanceOf(address _owner) public view returns (uint256) {
require(_owner != address(0));
return ownedTokensCount[_owner];
}

function ownerOf(uint256 _tokenId) public view returns (address) {
address owner = tokenOwner[_tokenId];
require(owner != address(0));
return owner;
}

function exists(uint256 _tokenId) public view returns (bool) {
address owner = tokenOwner[_tokenId];
return owner != address(0);
}

function approve(address _to, uint256 _tokenId) public {
address owner = ownerOf(_tokenId);
require(_to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

if (getApproved(_tokenId) != address(0) || _to != address(0)) {
  tokenApprovals[_tokenId] = _to;
  emit Approval(owner, _to, _tokenId);
    }
}

function getApproved(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}

function setApprovalForAll(address _to, bool _approved) public {
require(_to != msg.sender);
operatorApprovals[msg.sender][_to] = _approved;
emit ApprovalForAll(msg.sender, _to, _approved);
}

function isApprovedForAll(
address _owner,
address _operator
)
public
view
returns (bool)
{
return operatorApprovals[_owner][_operator];
}

function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
canTransfer(_tokenId)
{
require(_from != address(0));
require(_to != address(0));

clearApproval(_from, _tokenId);
removeTokenFrom(_from, _tokenId);
addTokenTo(_to, _tokenId);

    emit Transfer(_from, _to, _tokenId);
}

function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
canTransfer(_tokenId)
{
// solium-disable-next-line arg-overflow
safeTransferFrom(_from, _to, _tokenId, "");
}

function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public
canTransfer(_tokenId)
{
transferFrom(_from, _to, _tokenId);
// solium-disable-next-line arg-overflow
require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
}

function isApprovedOrOwner(
address _spender,
uint256 _tokenId
)
internal
view
returns (bool)
{
address owner = ownerOf(_tokenId);
// Disable solium check because of
// https://github.com/duaraghav8/Solium/issues/175
// solium-disable-next-line operator-whitespace
return (
  _spender == owner ||
  getApproved(_tokenId) == _spender ||
  isApprovedForAll(owner, _spender)
);
}

function _mint(address _to, uint256 _tokenId) internal {
require(_to != address(0));
addTokenTo(_to, _tokenId);
emit Transfer(address(0), _to, _tokenId);
}

function _burn(address _owner, uint256 _tokenId) internal {
clearApproval(_owner, _tokenId);
removeTokenFrom(_owner, _tokenId);
emit Transfer(_owner, address(0), _tokenId);
}

function clearApproval(address _owner, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _owner);
if (tokenApprovals[_tokenId] != address(0)) {
  tokenApprovals[_tokenId] = address(0);
  emit Approval(_owner, address(0), _tokenId);
}
}

function addTokenTo(address _to, uint256 _tokenId) internal {
require(tokenOwner[_tokenId] == address(0));
tokenOwner[_tokenId] = _to;
ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
}

function removeTokenFrom(address _from, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _from);
ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
tokenOwner[_tokenId] = address(0);
}

function checkAndCallSafeTransfer(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
internal
returns (bool)
{
if (!_to.isContract()) {
  return true;
}
bytes4 retval = ERC721Receiver(_to).onERC721Received(
  _from, _tokenId, _data);
return (retval == ERC721_RECEIVED);
}
}

To understand better all the steps that the inheritance from PausableToken has achieved in making our TestCoin a useful ERC721-compliant token (and why it can be helpful to start from an open source library like OpenZeppelin), you can follow closely the code of each of the library’s files that were imported after each inheritance and import is fully expanded.

For that, browsing the OpenZeppelin ERC721 token github repo will be very helpful: our TestCoin is inheriting from PausableToken, which itself inherits from StandardToken, which inherits from BasicToken and ERC721, and so on all the way to ERC721Basic and the SafeMath library import.

Developing your smart contract directly

Another way of doing this is to simply write the ERC721 interface and your contract implementing it directly from scratch. As you’ll see, this is actually a fairly straightforward task:

pragma solidity ^0.4.16;

contract ERC721Token {
  uint256 public totalSupply;

  function balanceOf(address _owner) public constant returns (uint256 balance);
  function transfer(address _to, uint256 _value) public returns (bool success);
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);

  function approve(address _spender, uint256 _value) public returns (bool success);

  function allowance(address _owner, address _spender) public constant returns (uint256 remaining);

  event Transfer(address indexed _from, address indexed _to, uint256 _value);
  event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

contract TestToken is ERC721Token {

  string  public name = "Test Coin";
  string  public symbol = "TEST";
  uint8   public decimals = 6;
  uint256 public INITIAL_SUPPLY = 100000000 * (10 ** uint256(decimals));

  mapping (address => uint256) balances;
  mapping (address => mapping (address => uint256)) allowed;

  function TestToken() {
    totalSupply = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }

  function transfer(address _to, uint256 _value) public returns (bool success) {
    require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
    require(_to != 0x0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
    balances[_to] += _value;
    balances[_from] -= _value;
    allowed[_from][msg.sender] -= _value;
    emit Transfer(_from, _to, _value);
    return true;
  }

  function balanceOf(address _owner) public constant returns (uint256 balance) {
    return balances[_owner];
  }

  function approve(address _spender, uint256 _value) public returns (bool success) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }
}

You can get this file directly from OpenZeppelin’s GitHub repo or copy paste the code above and edit it as needed. Make sure to save your contract to a local file on your computer (e.g. ERC721BasicToken.sol). However, the code is only for demonstration only.

Compile and deploy ERC721 token smart contract

As a next step, you’ll need to generate the bytecode and ABI for your new smart contract. You can think of the bytecode as basically your contract’s compiled code. The ABI (Application Binary Interface) is a JavaScript Object that defines how to interact with your smart contract.

We will show three ways of achieving this as well - using MOAC wallet, Remix web IDE for Solidity development, or compiling using the solc compiler on your machine (i.e. the command line).

Using MOAC wallet

MOAC wallet is an online free, client-side interface for using MOAC wallets, make transactions and deploy contract. It was developed based on open-source software. To use the service, you need to run a local MOAC node with addition command line arguments:

--rpccorsdomain "http://wallet.moac.io"

This will allow the access of MOAC node using MOAC wallet.

Otherwise you will see the following error message:

ERC20\_moacwallet01.png

ERC20_moacwallet01.png

Example command to start a MOAC node connecting with mainnet:

moac --rpccorsdomain "http://wallet.moac.io" --rpc --rpcport "8545" --rpcapi "chain3,mc,net,db"

A successful interface connecting to mainnet looks like this:

ERC20\_moacwallet02.png

ERC20_moacwallet02.png

To compile the contract, click the “CONTRACTS” icon:

ERC20\_moacwallet03.png

ERC20_moacwallet03.png

Then enter the contract deploy page:

ERC20\_moacwallet04.png

ERC20_moacwallet04.png

Copy the source code and paste in the “SOLIDITY CONTRACT SOURCE CODE” section. After copying the source code, the compiling process will automatically started. If no errors are not found, the right side should show a “SELECT CONTRACT TO DEPLOY” menu. |ERC20\_moacwallet05.png| Select the contract name “TokenERC721”: |ERC20\_moacwallet06.png| Input the parameters values from the menu: |ERC20\_moacwallet07.png| You need to have enough balance to deploy the contract. You can choose the amount of fee to use when deploying the contract. Click the DEPLOY button: |ERC20\_moacwallet08.png|

This is the contract ready to send from Account 1. The Provide gas is estimated by the compiler and we suggest you use it or put a larger number. If gas is not enough, the contract cannot be created. To continue, be sure to unlock the account to create the contract. You can use a console attached to the MOAC to do this:

ERC20\_moacwallet09.png

ERC20_moacwallet09.png

After deploying, the interface is returned to the main menu and you can see the following transaction is creating.

|ERC20\_moacwallet10.png| After 12 confirmations, you can start using the contract by click the admin page link. |ERC20\_moacwallet11.png|

MOAC wallet is good for beginners that only need basic contract development needs. It cannot debug contracts. To advanced developers, you can use Remix to work with contracts.

Remix

Remix is an online tool developed by Ethereum community to work with smart contracts. MOAC also supports the deploy of smart contract through Remix.

Open Remix on your browser, create a new file called ‘TestToken.sol’ and copy paste the code of your smart contract. Make sure you are including all the other Solidity files that your code is referencing with imports, especially if you are using the open source library approach.

Select ‘TestToken’ in the Compile window then click “Start to Compile” and the Details button next to TestToken. Upon scrolling in the popup details window for TestToken, you should be able to see similar sections to this Remix screenshot for the bytecode and ABI of your smart contract:

If the contract is compiled successfully, remix will show the interface like this:

|ERC20\_moacwallet12.png| To deploy the contract, you need to connect REMIX to a local or remote MOAC node. In addition to other arguments, be sure to enable the access of REMIX to the MOAC node with

moac --rpccorsdomain "http://remix.ethereum.org" --rpc --rpcport "8545" --rpcapi "chain3,mc,net,db"

Click the Run Tab and you should see the following menu: |ERC20\_moacwallet13.png|

Choose the Environment menu: JavaScript VM is a simulated environment of Remix, it can be use to debugging the contract without actually deploying the contract to a real network. Injected Web3 is the default web3 connecting to Ethereum network. To deploy MOAC contract, you need to choose Web3 Provider.

ERC20\_moacwallet14.png

ERC20_moacwallet14.png

After choose “Web3 Provider”, you can see a message like this:

Click “OK”,

ERC20\_moacwallet15.png

ERC20_moacwallet15.png

You need to make sure the port is the same as the local running node.

ERC20\_moacwallet12.png

ERC20_moacwallet12.png

You may see the error message like this:

|ERC20\_moacwallet17.png| If you see this error message, check the local node that include both

--rpccorsdomain "http://remix.ethereum.org"

and

--rpcport "8545"

If the connection is established, you should see your accounts from the Account List.

ERC20\_moacwallet18.png

ERC20_moacwallet18.png

Before you deploy the contract, you need to unlock the account that send the contract. You can do the unlock with the MOAC console:

ERC20\_moacwallet09.png

ERC20_moacwallet09.png

After successfully deployed the contract, you should see the contract address and other information showed in the menu:

ERC20\_moacwallet19.png

ERC20_moacwallet19.png

Remix is good for developing and debugging smart contracts. It is not very convenient to deploy multiple contracts. If your requires to deploy multiple contracts, you can use the Node.Js packages.

Using the Node.Js packages

You need to install solc package to compile the smart contract, and chain3 package to deploy the contract.

To use the latest stable version of the Solidity compiler via Node.js you can install it via npm:

npm install solc
var solc = require('solc')
var input = 'contract x { function g() {} }'
// Setting 1 as second paramateractivates the optimiser
var output = solc.compile(input, 1)
for (var contractName in output.contracts) {
        // code and ABI that are needed by web3
        console.log(contractName + ': ' + output.contracts[contractName].bytecode)
        console.log(contractName + '; ' + JSON.parse(output.contracts[contractName].interface))
}

To deploy the contracts, you need to install the Chain3 package:

npm install chain3

There is an example file in the package: example/contract_deploy.js

After successfully deploy, you should see the contract is displayed

Succeed!: 0x95d703ea48477f48335ae9c477ce6d986bc68453dfe3d6582714045456b93405

Using solc compiler to generate the ABI and bytecode Another way of generating these two files is to compile your smart contract using the solc compiler on your machine. If you haven’t used solc yet, you can follow these instructions for installing it on your machine.

Open a Terminal window and navigate to your working directory where you have saved your TestToken.sol file. Run the following command to export the ‘TestToken.abi’ and ‘TestToken.bin’ files to the bin directory:

solc --bin --abi -o bin TestToken.sol

As the file extensions suggest, ‘TestToken.abi’ contains your contract’s ABI, and ‘TestToken.bin’ contains its bytecode.

If you prefer accessing the solc compiler from within a program’s code to generate the ABI and bytecode files rather than using the command line, you can use the following code instead:

var fs =  require ( ' fs ' );
var solc =  requires ( 'solc' );

var cmds = process.argv;
if(cmds != null && cmds.length > 2){
  var file = cmds[2];
  var name = cmds[3];
  var content = fs.readFileSync(file).toString();

  was input = {
    file: content
  };

  var output = solc.compile({sources: input}, 1);
  console.log('contracts', Object.keys(output.contracts));

  var ctt = output.contracts[name];
  if(ctt == null){
      return;
  }

  var bytecode = ctt.bytecode;
  var abi = JSON.parse(ctt.interface);

  console.log('bytecode', bytecode);
  console.log('abi', ctt.interface);
}

Regardless of which method you followed, you should now have the ABI and bytecode files for your TestToken smart contract. Next, you will be able to deploy your token contract on the MOAC blockchain for others to interact with it.

Here are some FAQs from the community. If you cannot find your answers here or have more questions, please feel free to check Issues, or send an email to us.

Table of Contents

What is MOAC?

MOAC is a revolutionary platform with a Multi-Blockchain smart contract and P2P service network to efficiently build and scale decentralized applications. By leveraging Multi-Blockchain sharding, the MOAC platform increases system capacity and performance, reduces transaction fees for smart contracts, and incentivizes mobile and desktop users to compete for processing rewards.

The platform is a Multi-Blockchain software and deployment service solution for rapid development of decentralized applications (Dapps) and smart contracts on a scalable P2P service network. By using an advanced layered architecture for asynchronous smart contracts and a variety of configurable consensus systems (including “proof of work” and “proof of stake”), the MOAC platform enhances existing Dapps with additional functionality, and scalability solutions. This advancement increases processing speed by several levels of magnitude (10-100x) and sets a new market standard for transactional efficiency, while optimizing decentralization mechanisms and overall security.

What is MOAC for?

The MOAC platform was designed to increase and maximize blockchain network performance using node-based computing power and allowing for on-demand, timed, and savable smart contract processing. The platform provides tools and APIs to application developers to quickly build complex Dapps that can leverage both “proof of work” and “proof of stake” and other scalable consensus systems on a decentralized P2P service network. In turn, and as a result of increased volume and speed of processing, the new MotherChain standard incentivizes the user community and drives increased participation - including users with low processing power (i.e., mobile users).

Platform build for applications

  • New architecture for applications
  • Easy adoption, low cost
  • 100x TPS improvement over Ethereum

Open ecosystem

  • Smart Contract as a Micro-chain (SAAM)
  • Cross-chain capability
  • Two levels of mining encourage massive participants
MOAC structure

MOAC structure

Why was MOAC created?

Existing blockchain technologies and platforms suffer from steep learning curves, unnecessary complexity, and high usage fees all of which impact adoption and scalability. Technically, existing platforms have low transactions-per-second, have fixed consensus models, and are not able to quickly adapt to the ever growing needs of developers. These blockchain platforms are also alienated from each other, and unable to communicate effectively with other cryptocurrencies, smart contracts, and blockchain systems, creating a highly segregated blockchain marketplace. To make matters even more complicated, most blockchains are difficult to upgrade, and split participation inefficiently between users.

MOAC has addressed the primary inefficiencies of existing blockchain platforms by developing a Multi-Blockchain architecture that lowers Dapps costs, provides for scalability, and reduces development complexity while also increasing transaction speeds and volume using sharding. MOAC leverages multiple blockchains within its platform, including MotherChain (Proof of Work), a Dapp Chain (Proof of Stake or any other consensus protocol, see below sections) for scalable transactions, Microchains for Smart Contracts, and Cross-Chain capabilities for interacting between multiple blockchains and cryptocurrencies for improved efficiency, and scalability.

By separating balance transfer and smart contracts, the MOAC Platform can outperform Ethereum by 100x transactions per second using an advanced Mutli-blockchain system including Microchains and sharding.

Why is MOAC so much better for DAPPs?

First, MOAC uses blockchain sharding to speed up the TPS, making it an attractive platform for DAPP developers and users.

Secondly, it redefines how DAPP developers and users interact with the system from the monetization standpoint. Most existing systems assume unfair burden on DAPP users: not only DAPP do they have to pay each transaction fee, but they also have a steep learning curve to climb on how blockchain works. With MOAC, there is no need to know anything about the underlying system before using the DAPP, and no need to acquire any underlying token unless the use case itself really commands it.

Thirdly, MOAC adds new ways to redistribute tokens to a wide range of participants, thus further supporting decentralization. Thanks to the second layer’s mining, each DAPP will pay its miners continuously all throughout the lifetime of the DAPP. And because the second layer’s mining does not need to calculate a random number, every CPU (including mobile devices) can participate as potential nodes. This greatly encourages participants in masses to provide the processing power to support more DAPPs and get incentivized accordingly.

Finally, since DAPPs are deployed in a virtual machine of the developer’s choice, they do not require additional programming. MOAC is able to run existing Ethereum smart contracts with lower fees, and developers can leverage the MOAC API to expand their existing smart contract with additional functionality without having to learn how to program on the blockchain.

How to get MOAC?

MOAC’s mainnet was released on April 30th, 2018. Now you can get MOAC on the mainnet through the following options:

  1. User can mined the MOAC out using the released go client.
  2. If you have any ERC20 token, you can also exchange your ERC20 token to Moac on the mainnet by contacting .
  3. Exchange MOAC with other crypto-tokens: There are several exchanges that currently listed MOAC. You can find more info on this link.

If you want some moac on the testnet, you can mine on the testnet, put your receiver address here or contact the MOAC team.

moaclogo

moaclogo

Welcom to the MOAC Wiki!

欢迎来到墨客的世界!

Mother Of All Chains (MOAC) is to design a scalable and resilient Blockchain that supports transactions, data access, control flow in a layered structure. It creates the framework to allow users to execute Smart Contract in an efficient way. It also provides the architecture to spawn sub blockchains using underlying infrastructure quickly and easily. It is a Blockchain platform with necessary plumbing parts available to sub blockchains, providing solution for idea test, private chain deployment, complex task processing, decentralized applications etc.

Index

General Inforamtion

Introduction

VNODE

SCS

FAQs

Versions

ÐApp Development

ERC20

ERC721

How-To-Create-a-Wallet

Go to https://www.moacwalletonline.com/#generate-wallet .

Enter a strong but easy to remember password.

Click the “Create New Wallet” button.

Click the “Download” button & save your Keystore / UTC file. Back it up.

Read the warning. If you understand it and promise not to lose your private key, click the “I understand. Continue” button.

You now have the option of printing a paper wallet, saving your private key, or saving a QR code of your private key. Back up at least one (offline).

Then click “Next: Save your Address”

Unlock your wallet that you just created using the Keystore / UTC file you just downloaded or the private key.

Ensure all information matches. Don’t lose this information. Double check your work. Don’t be dumb.

Contents

JSON RPC API

JSON is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value pairs.

JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over HTTP, or in many various message passing environments. It uses JSON (RFC 4627) as data format.

Geth 1.4 has experimental pub/sub support. See this page for more information.

Parity 1.6 has experimental pub/sub support See this for more information.

JavaScript API

To talk to an ethereum node from inside a JavaScript application use the web3.js library, which gives a convenient interface for the RPC methods. See the JavaScript API for more.

JSON-RPC Endpoint

Default JSON-RPC endpoints:

Client URL
C++ http://localhost:8545
Go http://localhost:8545
Py http://localhost:4000
Parity http://localhost:8545

Go

You can start the HTTP JSON-RPC with the --rpc flag

geth --rpc

change the default port (8545) and listing address (localhost) with:

geth --rpc --rpcaddr <ip> --rpcport <portnumber>

If accessing the RPC from a browser, CORS will need to be enabled with the appropriate domain set. Otherwise, JavaScript calls are limit by the same-origin policy and requests will fail:

geth --rpc --rpccorsdomain "http://localhost:3000"

The JSON RPC can also be started from the geth console using the admin.startRPC(addr, port) command.

C++

You can start it by running eth application with -j option:

./eth -j

You can also specify JSON-RPC port (default is 8545):

./eth -j --json-rpc-port 8079

Python

In python the JSONRPC server is currently started by default and listens on 127.0.0.1:4000

You can change the port and listen address by giving a config option.

pyethapp -c jsonrpc.listen_port=4002 -c jsonrpc.listen_host=127.0.0.2 run

JSON-RPC support

  cpp-ethereum go-ethereum py-ethereum parity
JSON-RPC 1.0      
JSON-RPC 2.0
Batch requests
HTTP
IPC  
WS    

HEX value encoding

At present there are two key datatypes that are passed over JSON: unformatted byte arrays and quantities. Both are passed with a hex encoding, however with different requirements to formatting:

When encoding QUANTITIES (integers, numbers): encode as hex, prefix with “0x”, the most compact representation (slight exception: zero should be represented as “0x0”). Examples: - 0x41 (65 in decimal) - 0x400 (1024 in decimal) - WRONG: 0x (should always have at least one digit - zero is “0x0”) - WRONG: 0x0400 (no leading zeroes allowed) - WRONG: ff (must be prefixed 0x)

When encoding UNFORMATTED DATA (byte arrays, account addresses, hashes, bytecode arrays): encode as hex, prefix with “0x”, two hex digits per byte. Examples: - 0x41 (size 1, “A”) - 0x004200 (size 3, “:raw-latex:`\0`B:raw-latex:`0`”) - 0x (size 0, “”) - WRONG: 0xf0f0f (must be even number of digits) - WRONG: 004200 (must be prefixed 0x)

Currently cpp-ethereum,go-ethereum, and parity provide JSON-RPC communication over http and IPC (unix socket Linux and OSX/named pipes on Windows). Version 1.4 of go-ethereum and version 1.6 of Parity onwards have websocket support.

The default block parameter

The following methods have an extra default block parameter:

When requests are made that act on the state of ethereum, the last default block parameter determines the height of the block.

The following options are possible for the defaultBlock parameter:

  • HEX String - an integer block number
  • String "earliest" for the earliest/genesis block
  • String "latest" - for the latest mined block
  • String "pending" - for the pending state/transactions

Curl Examples Explained

The curl options below might return a response where the node complains about the content type, this is because the –data option sets the content type to application/x-www-form-urlencoded . If your node does complain, manually set the header by placing -H “Content-Type: application/json” at the start of the call.

The examples also do not include the URL/IP & port combination which must be the last argument given to curl e.x. 127.0.0.1:8545

JSON RPC API Reference


Returns the current client version.

none

String - The current client version

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc":"2.0",
  "result": "Mist/v0.9.3/darwin/go1.4.1"
}

Returns Keccak-256 (not the standardized SHA3-256) of the given data.

  1. DATA - the data to convert into a SHA3 hash
params: [
  "0x68656c6c6f20776f726c64"
]

DATA - The SHA3 result of the given string.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}'

// Result
{
  "id":64,
  "jsonrpc": "2.0",
  "result": "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"
}

Returns the current network id.

none

String - The current network id. - "1": Ethereum Mainnet - "2": Morden Testnet (deprecated) - "3": Ropsten Testnet - "4": Rinkeby Testnet - "42": Kovan Testnet

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc": "2.0",
  "result": "3"
}

Returns true if client is actively listening for network connections.

none

Boolean - true when listening, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"net_listening","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc":"2.0",
  "result":true
}

Returns number of peers currently connected to the client.

none

QUANTITY - integer of the number of connected peers.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":74}'

// Result
{
  "id":74,
  "jsonrpc": "2.0",
  "result": "0x2" // 2
}

Returns the current ethereum protocol version.

none

String - The current ethereum protocol version

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc": "2.0",
  "result": "54"
}

Returns an object with data about the sync status or false.

none

Object|Boolean, An object with sync status data or FALSE, when not syncing: - startingBlock: QUANTITY - The block at which the import started (will only be reset, after the sync reached his head) - currentBlock: QUANTITY - The current block, same as eth_blockNumber - highestBlock: QUANTITY - The estimated highest block

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": {
    startingBlock: '0x384',
    currentBlock: '0x386',
    highestBlock: '0x454'
  }
}
// Or when not syncing
{
  "id":1,
  "jsonrpc": "2.0",
  "result": false
}

Returns the client coinbase address.

none

DATA, 20 bytes - the current coinbase address.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_coinbase","params":[],"id":64}'

// Result
{
  "id":64,
  "jsonrpc": "2.0",
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}

Returns true if client is actively mining new blocks.

none

Boolean - returns true of the client is mining, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":71}'

// Result
{
  "id":71,
  "jsonrpc": "2.0",
  "result": true
}

Returns the number of hashes per second that the node is mining with.

none

QUANTITY - number of hashes per second.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_hashrate","params":[],"id":71}'

// Result
{
  "id":71,
  "jsonrpc": "2.0",
  "result": "0x38a"
}

Returns the current price per gas in wei.

none

QUANTITY - integer of the current gas price in wei.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":73}'

// Result
{
  "id":73,
  "jsonrpc": "2.0",
  "result": "0x09184e72a000" // 10000000000000
}

Returns a list of addresses owned by client.

none

Array of DATA, 20 Bytes - addresses owned by the client.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": ["0x407d73d8a49eeb85d32cf465507dd71d507100c1"]
}

Returns the number of most recent block.

none

QUANTITY - integer of the current block number the client is on.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}'

// Result
{
  "id":83,
  "jsonrpc": "2.0",
  "result": "0x4b7" // 1207
}

Returns the balance of the account of given address.

  1. DATA, 20 Bytes - address to check for balance.
  2. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter
params: [
   '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
   'latest'
]

QUANTITY - integer of the current balance in wei.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x0234c8a3397aab58" // 158972490234375000
}

Returns the value from a storage position at a given address.

  1. DATA, 20 Bytes - address of the storage.
  2. QUANTITY - integer of the position in the storage.
  3. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter

DATA - the value at this storage position.

Calculating the correct position depends on the storage to retrieve. Consider the following contract deployed at 0x295a70b2de5e3953354a6a8344e616ed314d7251 by address 0x391694e7e0b0cce554cb130d723a9d27458f9298.

contract Storage {
    uint pos0;
    mapping(address => uint) pos1;

    function Storage() {
        pos0 = 1234;
        pos1[msg.sender] = 5678;
    }
}

Retrieving the value of pos0 is straight forward:

curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"], "id": 1}' localhost:8545

{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000004d2"}

Retrieving an element of the map is harder. The position of an element in the map is calculated with:

keccack(LeftPad32(key, 0), LeftPad32(map position, 0))

This means to retrieve the storage on pos1[“0x391694e7e0b0cce554cb130d723a9d27458f9298”] we need to calculate the position with:

keccak(decodeHex("000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001"))

The geth console which comes with the web3 library can be used to make the calculation:

> var key = "000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001"
undefined
> web3.sha3(key, {"encoding": "hex"})
"0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9"

Now to fetch the storage:

curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9", "latest"], "id": 1}' localhost:8545

{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000162e"}

Returns the number of transactions sent from an address.

  1. DATA, 20 Bytes - address.
  2. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter
params: [
   '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
   'latest' // state at the latest block
]

QUANTITY - integer of the number of transactions send from this address.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1","latest"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

Returns the number of transactions in a block from a block matching the given block hash.

  1. DATA, 32 Bytes - hash of a block
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

QUANTITY - integer of the number of transactions in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockTransactionCountByHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xb" // 11
}

Returns the number of transactions in a block matching the given block number.
  1. QUANTITY|TAG - integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
params: [
   '0xe8', // 232
]

QUANTITY - integer of the number of transactions in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockTransactionCountByNumber","params":["0xe8"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xa" // 10
}

Returns the number of uncles in a block from a block matching the given block hash.

  1. DATA, 32 Bytes - hash of a block
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

QUANTITY - integer of the number of uncles in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleCountByBlockHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

Returns the number of uncles in a block from a block matching the given block number.

  1. QUANTITY|TAG - integer of a block number, or the string “latest”, “earliest” or “pending”, see the default block parameter
params: [
   '0xe8', // 232
]

QUANTITY - integer of the number of uncles in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleCountByBlockNumber","params":["0xe8"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

Returns code at a given address.

  1. DATA, 20 Bytes - address
  2. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter
params: [
   '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
   '0x2'  // 2
]

DATA - the code from the given address.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getCode","params":["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x2"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x600160008035811a818181146012578301005b601b6001356025565b8060005260206000f25b600060078202905091905056"
}

The sign method calculates an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).

By adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim.

Note the address to sign with must be unlocked.

account, message

  1. DATA, 20 Bytes - address
  2. DATA, N Bytes - message to sign

DATA: Signature

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sign","params":["0x9b2055d370f73ec7d8a03e965129118dc8f5bf83", "0xdeadbeaf"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b"
}

An example how to use solidity ecrecover to verify the signature calculated with eth_sign can be found here. The contract is deployed on the testnet Ropsten and Rinkeby.


Creates new message call transaction or a contract creation, if the data field contains code.

  1. Object - The transaction object
  • from: DATA, 20 Bytes - The address the transaction is send from.
  • to: DATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to.
  • gas: QUANTITY - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas.
  • gasPrice: QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas
  • value: QUANTITY - (optional) Integer of the value sent with this transaction
  • data: DATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI
  • nonce: QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
params: [{
  "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
  "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
  "gas": "0x76c0", // 30400
  "gasPrice": "0x9184e72a000", // 10000000000000
  "value": "0x9184e72a", // 2441406250
  "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]

DATA, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available.

Use eth_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

Creates new message call transaction or a contract creation for signed transactions.

  1. DATA, The signed transaction data.
params: ["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"]

DATA, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available.

Use eth_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

Executes a new message call immediately without creating a transaction on the block chain.

  1. Object - The transaction call object
  • from: DATA, 20 Bytes - (optional) The address the transaction is sent from.
  • to: DATA, 20 Bytes - The address the transaction is directed to.
  • gas: QUANTITY - (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions.
  • gasPrice: QUANTITY - (optional) Integer of the gasPrice used for each paid gas
  • value: QUANTITY - (optional) Integer of the value sent with this transaction
  • data: DATA - (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI
  1. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter

DATA - the return value of executed contract.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x"
}

Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain. Note that the estimate may be significantly more than the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance.

See eth_call parameters, expect that all properties are optional. If no gas limit is specified geth uses the block gas limit from the pending block as an upper bound. As a result the returned estimate might not be enough to executed the call/transaction when the amount of gas is higher than the pending block gas limit.

QUANTITY - the amount of gas used.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x5208" // 21000
}

Returns information about a block by hash.

  1. DATA, 32 Bytes - Hash of a block.
  2. Boolean - If true it returns the full transaction objects, if false only the hashes of the transactions.
params: [
   '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331',
   true
]

Object - A block object, or null when no block was found:

  • number: QUANTITY - the block number. null when its pending block.
  • hash: DATA, 32 Bytes - hash of the block. null when its pending block.
  • parentHash: DATA, 32 Bytes - hash of the parent block.
  • nonce: DATA, 8 Bytes - hash of the generated proof-of-work. null when its pending block.
  • sha3Uncles: DATA, 32 Bytes - SHA3 of the uncles data in the block.
  • logsBloom: DATA, 256 Bytes - the bloom filter for the logs of the block. null when its pending block.
  • transactionsRoot: DATA, 32 Bytes - the root of the transaction trie of the block.
  • stateRoot: DATA, 32 Bytes - the root of the final state trie of the block.
  • receiptsRoot: DATA, 32 Bytes - the root of the receipts trie of the block.
  • miner: DATA, 20 Bytes - the address of the beneficiary to whom the mining rewards were given.
  • difficulty: QUANTITY - integer of the difficulty for this block.
  • totalDifficulty: QUANTITY - integer of the total difficulty of the chain until this block.
  • extraData: DATA - the “extra data” field of this block.
  • size: QUANTITY - integer the size of this block in bytes.
  • gasLimit: QUANTITY - the maximum gas allowed in this block.
  • gasUsed: QUANTITY - the total used gas by all transactions in this block.
  • timestamp: QUANTITY - the unix timestamp for when the block was collated.
  • transactions: Array - Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter.
  • uncles: Array - Array of uncle hashes.
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true],"id":1}'

// Result
{
"id":1,
"jsonrpc":"2.0",
"result": {
    "number": "0x1b4", // 436
    "hash": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
    "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
    "nonce": "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "logsBloom": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
    "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
    "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
    "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a",
    "difficulty": "0x027f07", // 163591
    "totalDifficulty":  "0x027f07", // 163591
    "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "size":  "0x027f07", // 163591
    "gasLimit": "0x9f759", // 653145
    "gasUsed": "0x9f759", // 653145
    "timestamp": "0x54e34e8e" // 1424182926
    "transactions": [{...},{ ... }]
    "uncles": ["0x1606e5...", "0xd5145a9..."]
  }
}

Returns information about a block by block number.

  1. QUANTITY|TAG - integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
  2. Boolean - If true it returns the full transaction objects, if false only the hashes of the transactions.
params: [
   '0x1b4', // 436
   true
]

See eth_getBlockByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1b4", true],"id":1}'

Result see eth_getBlockByHash


Returns the information about a transaction requested by transaction hash.

  1. DATA, 32 Bytes - hash of a transaction
params: [
   "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"
]

Object - A transaction object, or null when no transaction was found:

  • hash: DATA, 32 Bytes - hash of the transaction.
  • nonce: QUANTITY - the number of transactions made by the sender prior to this one.
  • blockHash: DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.
  • blockNumber: QUANTITY - block number where this transaction was in. null when its pending.
  • transactionIndex: QUANTITY - integer of the transactions index position in the block. null when its pending.
  • from: DATA, 20 Bytes - address of the sender.
  • to: DATA, 20 Bytes - address of the receiver. null when its a contract creation transaction.
  • value: QUANTITY - value transferred in Wei.
  • gasPrice: QUANTITY - gas price provided by the sender in Wei.
  • gas: QUANTITY - gas provided by the sender.
  • input: DATA - the data send along with the transaction.
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'

// Result
{
"id":1,
"jsonrpc":"2.0",
"result": {
    "hash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
    "nonce":"0x",
    "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
    "blockNumber": "0x15df", // 5599
    "transactionIndex":  "0x1", // 1
    "from":"0x407d73d8a49eeb85d32cf465507dd71d507100c1",
    "to":"0x85h43d8a49eeb85d32cf465507dd71d507100c1",
    "value":"0x7f110", // 520464
    "gas": "0x7f110", // 520464
    "gasPrice":"0x09184e72a000",
    "input":"0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360",
  }
}

Returns information about a transaction by block hash and transaction index position.

  1. DATA, 32 Bytes - hash of a block.
  2. QUANTITY - integer of the transaction index position.
params: [
   '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331',
   '0x0' // 0
]

See eth_getTransactionByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByBlockHashAndIndex","params":["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "0x0"],"id":1}'

Result see eth_getTransactionByHash


Returns information about a transaction by block number and transaction index position.

  1. QUANTITY|TAG - a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
  2. QUANTITY - the transaction index position.
params: [
   '0x29c', // 668
   '0x0' // 0
]

See eth_getTransactionByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":1}'

Result see eth_getTransactionByHash


Returns the receipt of a transaction by transaction hash.

Note That the receipt is not available for pending transactions.

  1. DATA, 32 Bytes - hash of a transaction
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

Object - A transaction receipt object, or null when no receipt was found:

  • transactionHash: DATA, 32 Bytes - hash of the transaction.
  • transactionIndex: QUANTITY - integer of the transactions index position in the block.
  • blockHash: DATA, 32 Bytes - hash of the block where this transaction was in.
  • blockNumber: QUANTITY - block number where this transaction was in.
  • cumulativeGasUsed: QUANTITY - The total amount of gas used when this transaction was executed in the block.
  • gasUsed: QUANTITY - The amount of gas used by this specific transaction alone.
  • contractAddress: DATA, 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null.
  • logs: Array - Array of log objects, which this transaction generated.
  • logsBloom: DATA, 256 Bytes - Bloom filter for light clients to quickly retrieve related logs.

It also returns either :

  • root : DATA 32 bytes of post-transaction stateroot (pre Byzantium)
  • status: QUANTITY either 1 (success) or 0 (failure)
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'

// Result
{
"id":1,
"jsonrpc":"2.0",
"result": {
     transactionHash: '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238',
     transactionIndex:  '0x1', // 1
     blockNumber: '0xb', // 11
     blockHash: '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b',
     cumulativeGasUsed: '0x33bc', // 13244
     gasUsed: '0x4dc', // 1244
     contractAddress: '0xb60e8dd61c5d32be8058bb8eb970870f07233155', // or null, if none was created
     logs: [{
         // logs as returned by getFilterLogs, etc.
     }, ...],
     logsBloom: "0x00...0", // 256 byte bloom filter
     status: '0x1'
  }
}

Returns information about a uncle of a block by hash and uncle index position.

  1. DATA, 32 Bytes - hash a block.
  2. QUANTITY - the uncle’s index position.
params: [
   '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b',
   '0x0' // 0
]

See eth_getBlockByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockHashAndIndex","params":["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "0x0"],"id":1}'

Result see eth_getBlockByHash

Note: An uncle doesn’t contain individual transactions.


Returns information about a uncle of a block by number and uncle index position.

  1. QUANTITY|TAG - a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
  2. QUANTITY - the uncle’s index position.
params: [
   '0x29c', // 668
   '0x0' // 0
]

See eth_getBlockByHash

Note: An uncle doesn’t contain individual transactions.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":1}'

Result see eth_getBlockByHash


Returns a list of available compilers in the client.

none

Array - Array of available compilers.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getCompilers","params":[],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": ["solidity", "lll", "serpent"]
}

Returns compiled solidity code.

  1. String - The source code.
params: [
   "contract test { function multiply(uint a) returns(uint d) {   return a * 7;   } }",
]

DATA - The compiled source code.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["contract test { function multiply(uint a) returns(uint d) {   return a * 7;   } }"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": {
      "code": "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056",
      "info": {
        "source": "contract test {\n   function multiply(uint a) constant returns(uint d) {\n       return a * 7;\n   }\n}\n",
        "language": "Solidity",
        "languageVersion": "0",
        "compilerVersion": "0.9.19",
        "abiDefinition": [
          {
            "constant": true,
            "inputs": [
              {
                "name": "a",
                "type": "uint256"
              }
            ],
            "name": "multiply",
            "outputs": [
              {
                "name": "d",
                "type": "uint256"
              }
            ],
            "type": "function"
          }
        ],
        "userDoc": {
          "methods": {}
        },
        "developerDoc": {
          "methods": {}
        }
      }

}

Returns compiled LLL code.

  1. String - The source code.
params: [
   "(returnlll (suicide (caller)))",
]

DATA - The compiled source code.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileLLL","params":["(returnlll (suicide (caller)))"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x603880600c6000396000f3006001600060e060020a600035048063c6888fa114601857005b6021600435602b565b8060005260206000f35b600081600702905091905056" // the compiled source code
}

Returns compiled serpent code.

  1. String - The source code.
params: [
   "/* some serpent */",
]

DATA - The compiled source code.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileSerpent","params":["/* some serpent */"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x603880600c6000396000f3006001600060e060020a600035048063c6888fa114601857005b6021600435602b565b8060005260206000f35b600081600702905091905056" // the compiled source code
}

Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges.

Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters: * [] “anything” * [A] “A in first position (and anything after)” * [null, B] “anything in first position AND B in second position (and anything after)” * [A, B] “A in first position AND B in second position (and anything after)” * [[A, B], [A, B]] “(A OR B) in first position AND (A OR B) in second position (and anything after)”

  1. Object - The filter options:
  • fromBlock: QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
  • toBlock: QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
  • address: DATA|Array, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate.
  • topics: Array of DATA, - (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with “or” options.
params: [{
  "fromBlock": "0x1",
  "toBlock": "0x2",
  "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
  "topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]
}]

QUANTITY - A filter id.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"topics":["0x12341234"]}],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call eth_getFilterChanges.

None

QUANTITY - A filter id.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newBlockFilter","params":[],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":  "2.0",
  "result": "0x1" // 1
}

Creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call eth_getFilterChanges.

None

QUANTITY - A filter id.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newPendingTransactionFilter","params":[],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":  "2.0",
  "result": "0x1" // 1
}

Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren’t requested with eth_getFilterChanges for a period of time.

  1. QUANTITY - The filter id.
params: [
  "0xb" // 11
]

Boolean - true if the filter was successfully uninstalled, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_uninstallFilter","params":["0xb"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": true
}

Polling method for a filter, which returns an array of logs which occurred since last poll.

  1. QUANTITY - the filter id.
params: [
  "0x16" // 22
]

Array - Array of log objects, or an empty array if nothing has changed since last poll.

  • For filters created with eth_newBlockFilter the return are block hashes (DATA, 32 Bytes), e.g. ["0x3454645634534..."].
  • For filters created with eth_newPendingTransactionFilter the return are transaction hashes (DATA, 32 Bytes), e.g. ["0x6345343454645..."].
  • For filters created with eth_newFilter logs are objects with following params:
  • removed: TAG - true when the log was removed, due to a chain reorganization. false if its a valid log.
  • logIndex: QUANTITY - integer of the log index position in the block. null when its pending log.
  • transactionIndex: QUANTITY - integer of the transactions index position log was created from. null when its pending log.
  • transactionHash: DATA, 32 Bytes - hash of the transactions this log was created from. null when its pending log.
  • blockHash: DATA, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log.
  • blockNumber: QUANTITY - the block number where this log was in. null when its pending. null when its pending log.
  • address: DATA, 20 Bytes - address from which this log originated.
  • data: DATA - contains one or more 32 Bytes non-indexed arguments of the log.
  • topics: Array of DATA - Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.)
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterChanges","params":["0x16"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": [{
    "logIndex": "0x1", // 1
    "blockNumber":"0x1b4", // 436
    "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d",
    "transactionHash":  "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf",
    "transactionIndex": "0x0", // 0
    "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d",
    "data":"0x0000000000000000000000000000000000000000000000000000000000000000",
    "topics": ["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"]
    },{
      ...
    }]
}

Returns an array of all logs matching filter with given id.

  1. QUANTITY - The filter id.
params: [
  "0x16" // 22
]

See eth_getFilterChanges

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterLogs","params":["0x16"],"id":74}'

Result see eth_getFilterChanges


Returns an array of all logs matching a given filter object.

  1. Object - the filter object, see eth_newFilter parameters.
params: [{
  "topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]
}]

See eth_getFilterChanges

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]}],"id":74}'

Result see eth_getFilterChanges


Returns the hash of the current block, the seedHash, and the boundary condition to be met (“target”).

none

Array - Array with the following properties: 1. DATA, 32 Bytes - current block header pow-hash 2. DATA, 32 Bytes - the seed hash used for the DAG. 3. DATA, 32 Bytes - the boundary condition (“target”), 2^256 / difficulty.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getWork","params":[],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": [
      "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
      "0x5EED00000000000000000000000000005EED0000000000000000000000000000",
      "0xd1ff1c01710000000000000000000000d1ff1c01710000000000000000000000"
    ]
}

Used for submitting a proof-of-work solution.

  1. DATA, 8 Bytes - The nonce found (64 bits)
  2. DATA, 32 Bytes - The header’s pow-hash (256 bits)
  3. DATA, 32 Bytes - The mix digest (256 bits)
params: [
  "0x0000000000000001",
  "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "0xD1FE5700000000000000000000000000D1FE5700000000000000000000000000"
]

Boolean - returns true if the provided solution is valid, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0", "method":"eth_submitWork", "params":["0x0000000000000001", "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "0xD1GE5700000000000000000000000000D1GE5700000000000000000000000000"],"id":73}'

// Result
{
  "id":73,
  "jsonrpc":"2.0",
  "result": true
}

Used for submitting mining hashrate.

  1. Hashrate, a hexadecimal string representation (32 bytes) of the hash rate
  2. ID, String - A random hexadecimal(32 bytes) ID identifying the client
params: [
  "0x0000000000000000000000000000000000000000000000000000000000500000",
  "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c"
]

Boolean - returns true if submitting went through succesfully and false otherwise.

// Request
curl -X POST --data '{"jsonrpc":"2.0", "method":"eth_submitHashrate", "params":["0x0000000000000000000000000000000000000000000000000000000000500000", "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c"],"id":73}'

// Result
{
  "id":73,
  "jsonrpc":"2.0",
  "result": true
}

Stores a string in the local database.

Note this function is deprecated and will be removed in the future.

  1. String - Database name.
  2. String - Key name.
  3. String - String to store.
params: [
  "testDB",
  "myKey",
  "myString"
]

Boolean - returns true if the value was stored, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"db_putString","params":["testDB","myKey","myString"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": true
}

Returns string from the local database.

Note this function is deprecated and will be removed in the future.

  1. String - Database name.
  2. String - Key name.
params: [
  "testDB",
  "myKey",
]

String - The previously stored string.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"db_getString","params":["testDB","myKey"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": "myString"
}

Stores binary data in the local database.

Note this function is deprecated and will be removed in the future.

  1. String - Database name.
  2. String - Key name.
  3. DATA - The data to store.
params: [
  "testDB",
  "myKey",
  "0x68656c6c6f20776f726c64"
]

Boolean - returns true if the value was stored, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"db_putHex","params":["testDB","myKey","0x68656c6c6f20776f726c64"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": true
}

Returns binary data from the local database.

Note this function is deprecated and will be removed in the future.

  1. String - Database name.
  2. String - Key name.
params: [
  "testDB",
  "myKey",
]

DATA - The previously stored data.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"db_getHex","params":["testDB","myKey"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": "0x68656c6c6f20776f726c64"
}

Returns the current whisper protocol version.

none

String - The current whisper protocol version

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_version","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc": "2.0",
  "result": "2"
}

Sends a whisper message.

  1. Object - The whisper post object:
  • from: DATA, 60 Bytes - (optional) The identity of the sender.
  • to: DATA, 60 Bytes - (optional) The identity of the receiver. When present whisper will encrypt the message so that only the receiver can decrypt it.
  • topics: Array of DATA - Array of DATA topics, for the receiver to identify messages.
  • payload: DATA - The payload of the message.
  • priority: QUANTITY - The integer of the priority in a rang from … (?).
  • ttl: QUANTITY - integer of the time to live in seconds.
params: [{
  from: "0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1",
  to: "0x3e245533f97284d442460f2998cd41858798ddf04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a0d4d661997d3940272b717b1",
  topics: ["0x776869737065722d636861742d636c69656e74", "0x4d5a695276454c39425154466b61693532"],
  payload: "0x7b2274797065223a226d6",
  priority: "0x64",
  ttl: "0x64",
}]

Boolean - returns true if the message was send, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_post","params":[{"from":"0xc931d93e97ab07fe42d923478ba2465f2..","topics": ["0x68656c6c6f20776f726c64"],"payload":"0x68656c6c6f20776f726c64","ttl":0x64,"priority":0x64}],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": true
}

Creates new whisper identity in the client.

none

DATA, 60 Bytes - the address of the new identiy.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newIdentity","params":[],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xc931d93e97ab07fe42d923478ba2465f283f440fd6cabea4dd7a2c807108f651b7135d1d6ca9007d5b68aa497e4619ac10aa3b27726e1863c1fd9b570d99bbaf"
}

Checks if the client hold the private keys for a given identity.

  1. DATA, 60 Bytes - The identity address to check.
params: [
  "0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1"
]

Boolean - returns true if the client holds the privatekey for that identity, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_hasIdentity","params":["0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": true
}

(?)

none

DATA, 60 Bytes - the address of the new group. (?)

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newGroup","params":[],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xc65f283f440fd6cabea4dd7a2c807108f651b7135d1d6ca90931d93e97ab07fe42d923478ba2407d5b68aa497e4619ac10aa3b27726e1863c1fd9b570d99bbaf"
}

(?)

  1. DATA, 60 Bytes - The identity address to add to a group (?).
params: [
  "0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1"
]

Boolean - returns true if the identity was successfully added to the group, otherwise false (?).

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_addToGroup","params":["0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": true
}

Creates filter to notify, when client receives whisper message matching the filter options.

  1. Object - The filter options:
  • to: DATA, 60 Bytes - (optional) Identity of the receiver. When present it will try to decrypt any incoming message if the client holds the private key to this identity.
  • topics: Array of DATA - Array of DATA topics which the incoming message’s topics should match. You can use the following combinations:
    • [A, B] = A && B
    • [A, [B, C]] = A && (B || C)
    • [null, A, B] = ANYTHING && A && B null works as a wildcard
params: [{
   "topics": ['0x12341234bf4b564f'],
   "to": "0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1"
}]

QUANTITY - The newly created filter.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newFilter","params":[{"topics": ['0x12341234bf4b564f'],"to": "0x2341234bf4b2341234bf4b564f..."}],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": "0x7" // 7
}

Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren’t requested with shh_getFilterChanges for a period of time.

  1. QUANTITY - The filter id.
params: [
  "0x7" // 7
]

Boolean - true if the filter was successfully uninstalled, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_uninstallFilter","params":["0x7"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": true
}

Polling method for whisper filters. Returns new messages since the last call of this method.

Note calling the shh_getMessages method, will reset the buffer for this method, so that you won’t receive duplicate messages.

  1. QUANTITY - The filter id.
params: [
  "0x7" // 7
]

Array - Array of messages received since last poll:

  • hash: DATA, 32 Bytes (?) - The hash of the message.
  • from: DATA, 60 Bytes - The sender of the message, if a sender was specified.
  • to: DATA, 60 Bytes - The receiver of the message, if a receiver was specified.
  • expiry: QUANTITY - Integer of the time in seconds when this message should expire (?).
  • ttl: QUANTITY - Integer of the time the message should float in the system in seconds (?).
  • sent: QUANTITY - Integer of the unix timestamp when the message was sent.
  • topics: Array of DATA - Array of DATA topics the message contained.
  • payload: DATA - The payload of the message.
  • workProved: QUANTITY - Integer of the work this message required before it was send (?).
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getFilterChanges","params":["0x7"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": [{
    "hash": "0x33eb2da77bf3527e28f8bf493650b1879b08c4f2a362beae4ba2f71bafcd91f9",
    "from": "0x3ec052fc33..",
    "to": "0x87gdf76g8d7fgdfg...",
    "expiry": "0x54caa50a", // 1422566666
    "sent": "0x54ca9ea2", // 1422565026
    "ttl": "0x64", // 100
    "topics": ["0x6578616d"],
    "payload": "0x7b2274797065223a226d657373616765222c2263686...",
    "workProved": "0x0"
    }]
}

Get all messages matching a filter. Unlike shh_getFilterChanges this returns all messages.

  1. QUANTITY - The filter id.
params: [
  "0x7" // 7
]

See shh_getFilterChanges

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getMessages","params":["0x7"],"id":73}'

Result see shh_getFilterChanges

moaclogo # 欢迎来到墨客的世界!

MOAC旨在提供一种可扩展且有弹性的区块链,支持基于分层结构的状态交易,数据访问,和控制流程。它创建了一个框架以允许用户用高效的方式执行智能合约。它还提供了开发的体系结构,采用底层基础设施来快速简便地产生子区块链。它是一个区块链平台,可以为子区块链的架设提供必要的部件,为想法测试,私链部署,复杂任务处理和智能合同应用等提供解决方案。

分布式应用开发(ÐApp Development)

ERC20

ERC721

MOAC developed based on the Ethereum project. It also implements a *javascript runtime environment* (JSRE) that can be used in either interactive (console) or non-interactive (script) mode. It supports Dapp development through its own `chain3 <>`__ JavaScript API, just like web3.js on Ethereum.

If you want to develop Dapp on MOAC, you should use Solidity. MOAC supports the deployment of smart contracts through Remix, wallet.moac.io and For a Dapp that wants to move to MOAC from Ethereum, please follow these steps:

  1. Deploy the smart contract:

    You can check the two examples in our wiki page:

    ERC20

    ERC721

  2. Interact with the smart contract:

    • chain3, developed based on web3.js 0.2.x, is the JavaScript library supported by MOAC.
    • web3.js, only the functions listed in chain3 are workable, such as web3, eth, admin.

Protecting Yourself and Your Funds

  1. Bookmark your crypto sites. Use those bookmarks and only those.
  2. Install the EAL Chrome Extension or the MetaMask Chrome Extension to warn you if you go to a crypto-phishing link.
  3. Use MoacWalletOnline Locally / Offline.
  4. Do not trust messages or addresses or URLs sent via private message. Always verify information w/ a secondary source. Don’t click any link regarding anything crypto, money, banking, or a service like Dropbox / Google Drive / Gmail in any email ever. And if the scammy clickbait was simply too irresistible for you, don’t enter any information on the page. Never enter your private keys, passwords, sensitive data on a website that you were sent via message
  5. Turn on 2FA for everything. Go do it. Right now. Quit your excuses. Choose Google Authenticator over Authy. Don’t use your phone number. Then, make sure your phone number is NOT tied to your Google account (look in privacy settings). Turns out, you and your BFF Mr. Hacker can “recover” access to your account via that number, completely destroying the point of 2FA. PS: MyEtherWallet is client-side, meaning 2FA won’t do anything in our case. 2FA is for ensuring the security of your password on a server. PSS: Don’t forget to cold-storage your backup words for these 2FA things. It’s a huge pain when your phone goes for a swim and your entire life is 2FA’d. ?
  6. For Token Sales: do not trust any address except the one posted on the official site. Bookmark the URL before the sale, get the address from the URL from your bookmark at time of purchase. Do not trust any other source (especially a random bot on Slack). PS: When are token sales going to start using ENS names?
  7. Double check the URL & Triple check Github URLs. Check it. Then, check it again right before entering any information. This is especially important for any sites that require usernames, passwords, email addresses, private keys, and any other personal information. SSL certs do not mean a site is trustworthy, just that they bought an SSL cert. Not sure about the correct URL? Cross reference Reddit, Twitter, Github, Slack and wherever else the project hangs out. Github URLs are much easier to fake and much easier to miss. Instead of downloading from that random URL on reddit, seek out the URL on your own. Following the developers of these repos on Twitter, friending them on reddit (lol…but seriously it’s nice because their name will be orange), or starring said repos on Github helps.
  8. Always verify that the site you landed on is legit. Especially if you are about to enter your private key or download an application. What is legit? A service that people have used for a decent period of time with good results. If the URL has been registered in the last week or the site “just launched”, err on the side of caution and avoid it for a while.
  9. Google the service name + “scam” or “reviews” Scam sites rarely last long. Value real comments by real people over a random blog. Value a collection of information over a single source. Understand that legit services will likely have a mix of positive and negative reviews over a long period of time. Scam sites typically have no one talking about them, everyone yelling about how they got robbed, or the most perfect reviews ever. The latter one is just as red of a flag as the first one.
  10. Don’t ever run remote-access software (e.g. TeamViewer) Don’t ever…but especially not on a computer with keys on them. The number of security holes in these programs is atrocious. You 2FA your entire life, but then let a single string of characters give someone access to your entire computer & every account. ?
  11. Don’t use brain wallets Brain wallets are wallets where the key is derived from a word or phrase you choose. Human brains don’t have the ability to create high-entropy seeds. Using a phrase that you make up, even if it seems “rare” or “random” is not as secure as using MoacWalleOnline’s randomness and these phrases can be bruteforced by the millions. Read more. And more.
  12. Install an adblocker that actually turns off Google/Bing Ads. I recommend going with uBlock Orgin. If you are already using Adblock Plus, it does not hide Google Ads from you. Go into your Adblock Plus settings and uncheck the box that says “Allow some non-intrusive advertising”.
  13. Don’t click on advertisements. With or without an adblocker, you should never, ever click on advertisements.
  14. If you have accidentally visited or typed a malicious site, clean out your recent history and autocomplete. This will prevent you from typing kra… and having it autocomplete to the malicious krakken.com.
  15. No one is giving you free or discounted MOAC. Even for completing a survey. ;)
  16. The guys who just finish their token sale don’t want to sell you tokens via Slack DM. Neither does that smokin’ hot 125px x 125px avatar.
  17. Download the MoacWalletOnline Chrome Extension.
  18. ONLY unlock your wallet when you want to send a transaction. Check your balance via https://explorer.moac.io/ for mainnet.
  19. Lastly: use your brain Think for a moment. Don’t assume, ask. Don’t blindly follow, question. If something doesn’t seem right…if you feel like the luckiest fucker on Earth…or if you find yourself asking, “I wonder why I haven’t seen this on reddit yet”, there is likely a reason.

JSON RPC API

JSON is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value pairs.

JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over HTTP, or in many various message passing environments. It uses JSON (RFC 4627) as data format.

JavaScript API

To talk to a MOAC node from inside a JavaScript application use the chain3.js library, which gives a convenient interface for the RPC methods. See the JavaScript API for more.

JSON-RPC Endpoint

Default JSON-RPC endpoints:

Client URL
Go http://localhost:8545

Go

You can start the HTTP JSON-RPC with the --rpc flag

moac --rpc

change the default port (8545) and listing address (localhost) with:

moac --rpc --rpcaddr <ip> --rpcport <portnumber>

If accessing the RPC from a browser, CORS will need to be enabled with the appropriate domain set. Otherwise, JavaScript calls are limit by the same-origin policy and requests will fail:

moac --rpc --rpccorsdomain "http://localhost:3000"

The JSON RPC can also be started from the moac console using the admin.startRPC(addr, port) command.

HEX value encoding

At present there are two key datatypes that are passed over JSON: unformatted byte arrays and quantities. Both are passed with a hex encoding, however with different requirements to formatting:

When encoding QUANTITIES (integers, numbers): encode as hex, prefix with “0x”, the most compact representation (slight exception: zero should be represented as “0x0”). Examples: - 0x41 (65 in decimal) - 0x400 (1024 in decimal) - WRONG: 0x (should always have at least one digit - zero is “0x0”) - WRONG: 0x0400 (no leading zeroes allowed) - WRONG: ff (must be prefixed 0x)

When encoding UNFORMATTED DATA (byte arrays, account addresses, hashes, bytecode arrays): encode as hex, prefix with “0x”, two hex digits per byte. Examples: - 0x41 (size 1, “A”) - 0x004200 (size 3, “:raw-latex:`\0`B:raw-latex:`0`”) - 0x (size 0, “”) - WRONG: 0xf0f0f (must be even number of digits) - WRONG: 004200 (must be prefixed 0x)

Currently MOAC provides JSON-RPC communication over http and IPC (unix socket Linux and OSX/named pipes on Windows).

The default block parameter

The following methods have an extra default block parameter:

When requests are made that act on the state of ethereum, the last default block parameter determines the height of the block.

The following options are possible for the defaultBlock parameter:

  • HEX String - an integer block number
  • String "earliest" for the earliest/genesis block
  • String "latest" - for the latest mined block
  • String "pending" - for the pending state/transactions

Curl Examples Explained

The curl options below might return a response where the node complains about the content type, this is because the –data option sets the content type to application/x-www-form-urlencoded . If your node does complain, manually set the header by placing -H “Content-Type: application/json” at the start of the call.

The examples assume a local MOAC node is running and connected to testnet (network id = 101). The URL/IP & port combination is localhost:8545 or ‘127.0.0.1’, which must be the last argument given to curl.

JSON RPC API Reference


Returns the current client version.

none

String - The current client version

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"chain3_clientVersion","params":[],"id":101}' 'localhost:8545'

// Result
{
  "jsonrpc":"2.0",
  "id":101,
  "result":"Moac/v0.8.3-release-ad500ab5/darwin-amd64/go1.10"
}

Returns Keccak-256 (not the standardized SHA3-256) of the given data.

  1. DATA - the data to convert into a SHA3 hash
params: [
  "0x68656c6c6f20776f726c64"
]

DATA - The SHA3 result of the given string.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"chain3_sha3","params":["0x68656c6c6f20776f726c64"],"id":101}' localhost:8545

// Result
{
  "jsonrpc":"2.0",
  "id":101,
  "result":"0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"
}

Returns the current network id.

none

String - The current network id. - "99": MOAC Mainnet - "101": MOAC Testnet - "100": Devnet

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "101"
}

Returns true if client is actively listening for network connections.

none

Boolean - true when listening, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"net_listening","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc":"2.0",
  "result":true
}

Returns number of peers currently connected to the client.

none

QUANTITY - integer of the number of connected peers.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":101}' localhost:8545

// Result
{
  "id":74,
  "jsonrpc": "2.0",
  "result": "0x4" // 4 net peers are connecting
}

Returns the current MOAC protocol version.

none

String - The current MOAC protocol version

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_protocolVersion","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x3f"
}

Returns an object with data about the sync status or false.

none

Object|Boolean, An object with sync status data or FALSE, when not syncing: - startingBlock: QUANTITY - The block at which the import started (will only be reset, after the sync reached his head) - currentBlock: QUANTITY - The current block, same as mc_blockNumber - highestBlock: QUANTITY - The estimated highest block

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_syncing","params":[],"id":101}' localhost:8545

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": {
    startingBlock: '0x384',
    currentBlock: '0x386',
    highestBlock: '0x454'
  }
}
// Or when not syncing
{
  "id":101,
  "jsonrpc": "2.0",
  "result": false
}

Returns the client coinbase address.

none

DATA, 20 bytes - the current coinbase address.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_coinbase","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}

Returns true if client is actively mining new blocks.

none

Boolean - returns true of the client is mining, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_mining","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": true
}

Returns the number of hashes per second that the node is mining with.

none

QUANTITY - number of hashes per second.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_hashrate","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x38a"
}

Returns the current price per gas in sha.

none

QUANTITY - integer of the current gas price in sha.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_gasPrice","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x09184e72a000" // 10000000000000
}

Returns a list of addresses owned by client.

none

Array of DATA, 20 Bytes - addresses owned by the client.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_accounts","params":[],"id":101}' localhost:8545

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": ["0x407d73d8a49eeb85d32cf465507dd71d507100c1","0x87dc9d8014e189b9d32c622a9ad1d02f72383979"]
}

Returns the number of most recent block.

none

QUANTITY - integer of the current block number the client is on.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_blockNumber","params":[],"id":101}' 'localhost:8545'

// Result
{
  "id":83,
  "jsonrpc": "2.0",
  "result": "0x4b7" // 1207
}

Returns the balance of the account of given address.

  1. DATA, 20 Bytes - address to check for balance.
  2. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter
params: [
   '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
   'latest'
]

QUANTITY - integer of the current balance in sha.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getBalance","params":["0x87dc9d8014e189b9d32c622a9ad1d02f72383979", "latest"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x12f8b3a319c000" // 5340000000000000
}

Returns the value from a storage position at a given address.

  1. DATA, 20 Bytes - address of the storage.
  2. QUANTITY - integer of the position in the storage.
  3. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter

DATA - the value at this storage position.

Calculating the correct position depends on the storage to retrieve. Consider the following contract deployed at 0x02701dc451e126316ece6870fd70ea140efa7b15 by address 0xa8863fc8ce3816411378685223c03daae9770ebb.

contract Storage {
    uint pos0;
    mapping(address => uint) pos1;

    function Storage() {
        pos0 = 1234;
        pos1[msg.sender] = 5678;
    }
}

Retrieving the value of pos0 is straight forward:

curl -X POST --data '{"jsonrpc":"2.0", "method": "mc_getStorageAt", "params": ["0x02701dc451e126316ece6870fd70ea140efa7b15", "0x0", "latest"], "id": 101}' localhost:8545

{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000004d2"}

Retrieving an element of the map is harder. The position of an element in the map is calculated with:

keccack(LeftPad32(key, 0), LeftPad32(map position, 0))

This means to retrieve the storage on pos1[“0x391694e7e0b0cce554cb130d723a9d27458f9298”] we need to calculate the position with:

keccak(decodeHex("000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001"))

The moac console which comes with the chain3 library can be used to make the calculation:

> var key = "000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001"
undefined
> chain3.sha3(key, {"encoding": "hex"})
"0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9"

Now to fetch the storage:

curl -X POST --data '{"jsonrpc":"2.0", "method": "mc_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9", "latest"], "id": 101}' localhost:8545

{"jsonrpc":"2.0","id":101,"result":"0x000000000000000000000000000000000000000000000000000000000000162e"}

Returns the number of transactions sent from an address.

  1. DATA, 20 Bytes - address.
  2. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter
params: [
   '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
   'latest' // state at the latest block
]

QUANTITY - integer of the number of transactions send from this address.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getTransactionCount","params":["0x57d83802a772adf506a89f5021c93a05749e3c6e","latest"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x29" // 41
}

Returns the number of transactions in a block from a block matching the given block hash.

  1. DATA, 32 Bytes - hash of a block
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

QUANTITY - integer of the number of transactions in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getBlockTransactionCountByHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":101}' localhost:8545

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xb" // 11
}

Returns the number of transactions in a block matching the given block number.
  1. QUANTITY|TAG - integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
params: [
   '0xe8', // 232
]

QUANTITY - integer of the number of transactions in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getBlockTransactionCountByNumber","params":["0xe8"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0xa" // 10
}

Returns the number of uncles in a block from a block matching the given block hash.

  1. DATA, 32 Bytes - hash of a block
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

QUANTITY - integer of the number of uncles in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getUncleCountByBlockHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

Returns the number of uncles in a block from a block matching the given block number.

  1. QUANTITY|TAG - integer of a block number, or the string “latest”, “earliest” or “pending”, see the default block parameter
params: [
   '0xe8', // 232
]

QUANTITY - integer of the number of uncles in this block.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getUncleCountByBlockNumber","params":["0xe8"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

Returns code at a given address.

  1. DATA, 20 Bytes - address
  2. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter
params: [
   '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
   '0x2'  // 2
]

DATA - the code from the given address.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getCode","params":["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x2"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x600160008035811a818181146012578301005b601b6001356025565b8060005260206000f25b600060078202905091905056"
}

The sign method calculates an MOAC specific signature with: sign(keccak256("\x19MOAC Signed Message:\n" + len(message) + message))).

By adding a prefix to the message makes the calculated signature recognisable as an MOAC specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim.

Note the address to sign with must be unlocked.

account, message

  1. DATA, 20 Bytes - address
  2. DATA, N Bytes - message to sign

DATA: Signature

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_sign","params":["0x57d83802a772adf506a89f5021c93a05749e3c6e", "0xdeadbeaf"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0xefa354f816ab378a7da6ec25afe9e6393b72a3c06b2d08550815cc43d1993f6c58afbf228559df6a39ac419bef847ca2dc3047886df6a0f06a4c5e6a4e2dc9a61c"
}

An example how to use solidity ecrecover to verify the signature calculated with mc_sign can be found here. The contract is deployed on the testnet Ropsten and Rinkeby.


Creates new message call transaction or a contract creation, if the data field contains code.

Note the address to sign with must be unlocked.

  1. Object - The transaction object
  • from: DATA, 20 Bytes - The address the transaction is send from.
  • to: DATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to.
  • gas: QUANTITY - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas.
  • gasPrice: QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas
  • value: QUANTITY - (optional) Integer of the value sent with this transaction
  • data: DATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI
  • nonce: QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
params: [{
  "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
  "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
  "gas": "0x76c0", // 30400
  "gasPrice": "0x9184e72a000", // 10000000000000
  "value": "0x9184e72a", // 2441406250
  "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]

DATA, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available.

Use mc_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_sendTransaction","params":[{see above}],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

Creates new message call transaction or a contract creation for signed transactions.

  1. DATA, The signed transaction data.
params: ["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"]

DATA, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available.

Use mc_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_sendRawTransaction","params":[{see above}],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

Executes a new message call immediately without creating a transaction on the block chain.

  1. Object - The transaction call object
  • from: DATA, 20 Bytes - (optional) The address the transaction is sent from.
  • to: DATA, 20 Bytes - The address the transaction is directed to.
  • gas: QUANTITY - (optional) Integer of the gas provided for the transaction execution. mc_call consumes zero gas, but this parameter may be needed by some executions.
  • gasPrice: QUANTITY - (optional) Integer of the gasPrice used for each paid gas
  • value: QUANTITY - (optional) Integer of the value sent with this transaction
  • data: DATA - (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI
  1. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter

DATA - the return value of executed contract.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_call","params":[{see above}],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x"
}

Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain. Note that the estimate may be significantly more than the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance.

See mc_call parameters, expect that all properties are optional. If no gas limit is specified moac uses the block gas limit from the pending block as an upper bound. As a result the returned estimate might not be enough to executed the call/transaction when the amount of gas is higher than the pending block gas limit.

QUANTITY - the amount of gas used.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_estimateGas","params":[{see above}],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x5208" // 21000
}

Returns information about a block by hash.

  1. DATA, 32 Bytes - Hash of a block.
  2. Boolean - If true it returns the full transaction objects, if false only the hashes of the transactions.
params: [
   '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331',
   true
]

Object - A block object, or null when no block was found:

  • number: QUANTITY - the block number. null when its pending block.
  • hash: DATA, 32 Bytes - hash of the block. null when its pending block.
  • parentHash: DATA, 32 Bytes - hash of the parent block.
  • nonce: DATA, 8 Bytes - hash of the generated proof-of-work. null when its pending block.
  • sha3Uncles: DATA, 32 Bytes - SHA3 of the uncles data in the block.
  • logsBloom: DATA, 256 Bytes - the bloom filter for the logs of the block. null when its pending block.
  • transactionsRoot: DATA, 32 Bytes - the root of the transaction trie of the block.
  • stateRoot: DATA, 32 Bytes - the root of the final state trie of the block.
  • receiptsRoot: DATA, 32 Bytes - the root of the receipts trie of the block.
  • miner: DATA, 20 Bytes - the address of the beneficiary to whom the mining rewards were given.
  • difficulty: QUANTITY - integer of the difficulty for this block.
  • totalDifficulty: QUANTITY - integer of the total difficulty of the chain until this block.
  • extraData: DATA - the “extra data” field of this block.
  • size: QUANTITY - integer the size of this block in bytes.
  • gasLimit: QUANTITY - the maximum gas allowed in this block.
  • gasUsed: QUANTITY - the total used gas by all transactions in this block.
  • timestamp: QUANTITY - the unix timestamp for when the block was collated.
  • transactions: Array - Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter.
  • uncles: Array - Array of uncle hashes.
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getBlockByHash","params":["0x9d88f2a2a348eec743b149f461fddcf0843d3920ddf998896672cee476b99127", true],"id":101}' localhost:8545

// Result
{
"jsonrpc":"2.0",
"id":101,
"result":{
  "difficulty":"0x9ad5136",
  "extraData":"0xdd854d4f41432d85302e382e332d87676f312e382e338777696e646f7773",
  "gasLimit":"0x895440",
  "gasUsed":"0x0",
  "hash":"0x9d88f2a2a348eec743b149f461fddcf0843d3920ddf998896672cee476b99127",
  "logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "miner":"0x0a2168d2f08161c01745fec4e6e8fe06f314ab41",
  "mixHash":"0xd6e9f8d36f8f0f57abff5ccf6390ece4d5a14eb624779628fd6e6119451589e2",
  "nonce":"0x423e7acb4d05a23c",
  "number":"0x4803d",
  "parentHash":"0xc494dbda1ef4f673fd14fc487a1346a7747a41910d1a1f0e72d6e0e660c0e792",
  "receiptsRoot":"0x9287370eb27f11b0c2188431cbc58a23b685f02dbd851ed4d974f932bd780839",
  "sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "size":"0x24e",
  "stateRoot":"0xff791a26fd0cb6addfe4bec0287b3905bf44898f0fd71e446cb1385f94333e18",
  "timestamp":"0x5b1f3a14",
  "totalDifficulty":"0x325dc638b38e",
  "transactions":[{"blockHash":"0x9d88f2a2a348eec743b149f461fddcf0843d3920ddf998896672cee476b99127","blockNumber":"0x4803d","from":"0x0000000000000000000000000000000000000064","gas":"0x0","gasPrice":"0x4a817c800","hash":"0x52ccd05bdfb137fcbb6154f1cb7c006ba53cd8ce80511841d2e7b3c6324d49df","input":"0xc1c0e9c4","nonce":"0x4803c","syscnt":"0x65","to":"0x0000000000000000000000000000000000000065","transactionIndex":"0x0","value":"0x0","v":"0x0","r":"0x0","s":"0x0","shardingFlag":"0x0"}],
  "transactionsRoot":"0xa29e25d8e3db000e44122a594cc52a7bf050850b3a7e028fd54cb83784fc1bc3",
  "uncles":[]
  }
}

Returns information about a block by block number.

  1. QUANTITY|TAG - integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
  2. Boolean - If true it returns the full transaction objects, if false only the hashes of the transactions.
params: [
   '0x1b4', // 436
   true
]

See mc_getBlockByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getBlockByNumber","params":["0x1b4", true],"id":101}' localhost:8545

Result see mc_getBlockByHash


Returns the information about a transaction requested by transaction hash.

  1. DATA, 32 Bytes - hash of a transaction
params: [
   "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"
]

Object - A transaction object, or null when no transaction was found:

  • hash: DATA, 32 Bytes - hash of the transaction.
  • nonce: QUANTITY - the number of transactions made by the sender prior to this one.
  • blockHash: DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.
  • blockNumber: QUANTITY - block number where this transaction was in. null when its pending.
  • transactionIndex: QUANTITY - integer of the transactions index position in the block. null when its pending.
  • from: DATA, 20 Bytes - address of the sender.
  • to: DATA, 20 Bytes - address of the receiver. null when its a contract creation transaction.
  • value: QUANTITY - value transferred in Wei.
  • gasPrice: QUANTITY - gas price provided by the sender in Wei.
  • gas: QUANTITY - gas provided by the sender.
  • input: DATA - the data send along with the transaction.
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getTransactionByHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":101}' localhost:8545

// Result
{
"id":101,
"jsonrpc":"2.0",
"result": {
    "hash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
    "nonce":"0x",
    "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
    "blockNumber": "0x15df", // 5599
    "transactionIndex":  "0x1", // 1
    "from":"0x407d73d8a49eeb85d32cf465507dd71d507100c1",
    "to":"0x85h43d8a49eeb85d32cf465507dd71d507100c1",
    "value":"0x7f110", // 520464
    "gas": "0x7f110", // 520464
    "gasPrice":"0x09184e72a000",
    "input":"0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360",
  }
}

Returns information about a transaction by block hash and transaction index position.

  1. DATA, 32 Bytes - hash of a block.
  2. QUANTITY - integer of the transaction index position.
params: [
   '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331',
   '0x0' // 0
]

See mc_getTransactionByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getTransactionByBlockHashAndIndex","params":["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "0x0"],"id":101}' localhost:8545

Result see mc_getTransactionByHash


Returns information about a transaction by block number and transaction index position.

  1. QUANTITY|TAG - a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
  2. QUANTITY - the transaction index position.
params: [
   '0x29c', // 668
   '0x0' // 0
]

See mc_getTransactionByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getTransactionByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":101}' localhost:8545

Result see mc_getTransactionByHash


Returns the receipt of a transaction by transaction hash.

Note That the receipt is not available for pending transactions.

  1. DATA, 32 Bytes - hash of a transaction
params: [
   '0x7bb694c3462764cb113e9b742faaf06adc728e70b607f8b7aa95207ee32b1c5e'
]

Object - A transaction receipt object, or null when no receipt was found:

  • transactionHash: DATA, 32 Bytes - hash of the transaction.
  • transactionIndex: QUANTITY - integer of the transactions index position in the block.
  • blockHash: DATA, 32 Bytes - hash of the block where this transaction was in.
  • blockNumber: QUANTITY - block number where this transaction was in.
  • cumulativeGasUsed: QUANTITY - The total amount of gas used when this transaction was executed in the block.
  • gasUsed: QUANTITY - The amount of gas used by this specific transaction alone.
  • contractAddress: DATA, 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null.
  • logs: Array - Array of log objects, which this transaction generated.
  • logsBloom: DATA, 256 Bytes - Bloom filter for light clients to quickly retrieve related logs.

It also returns either :

  • root : DATA 32 bytes of post-transaction stateroot (pre Byzantium)
  • status: QUANTITY either 1 (success) or 0 (failure)
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getTransactionReceipt","params":["0x7bb694c3462764cb113e9b742faaf06adc728e70b607f8b7aa95207ee32b1c5e"],"id":101}' localhost:8545

// Result
{
{"jsonrpc":"2.0",
"id":101,
"result":{
"blockHash":"0xad7d2eec610b3e04ea4676c11a3184cb07df43ed7ab717f331d3c952fc1b55cf",
"blockNumber":"0x1b943",
"contractAddress":"0xf2f4eec6c2adfcf780aae828de0b25f86506ffae",
"cumulativeGasUsed":"0x1b337c",
"from":"0x7312f4b8a4457a36827f185325fd6b66a3f8bb8b",
"gasUsed":"0x1b337c",
"logs":[],
"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status":"0x1",
"to":null,
"transactionHash":"0x7bb694c3462764cb113e9b742faaf06adc728e70b607f8b7aa95207ee32b1c5e",
"transactionIndex":"0x1"}
}

Returns information about a uncle of a block by hash and uncle index position.

  1. DATA, 32 Bytes - hash a block.
  2. QUANTITY - the uncle’s index position.
params: [
   '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b',
   '0x0' // 0
]

See mc_getBlockByHash

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getUncleByBlockHashAndIndex","params":["0x696d389aa9b6b44e08af9f3528c51587aac435b75a54ece42f4b2d1289043497", "0x0"],"id":101}' localhost:8545

Result see mc_getBlockByHash

Note: An uncle doesn’t contain individual transactions.


Returns information about a uncle of a block by number and uncle index position.

  1. QUANTITY|TAG - a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
  2. QUANTITY - the uncle’s index position.
params: [
   '0x29c', // 668
   '0x0' // 0
]

See mc_getBlockByHash

Note: An uncle doesn’t contain individual transactions.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getUncleByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":101}' localhost:8545

Result see mc_getBlockByHash


Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call mc_getFilterChanges.

Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters: * [] “anything” * [A] “A in first position (and anything after)” * [null, B] “anything in first position AND B in second position (and anything after)” * [A, B] “A in first position AND B in second position (and anything after)” * [[A, B], [A, B]] “(A OR B) in first position AND (A OR B) in second position (and anything after)”

  1. Object - The filter options:
  • fromBlock: QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
  • toBlock: QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
  • address: DATA|Array, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate.
  • topics: Array of DATA, - (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with “or” options.
params: [{
  "fromBlock": "0x1",
  "toBlock": "0x2",
  "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
  "topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]
}]

QUANTITY - A filter id.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_newFilter","params":[{"topics":["0x12341234"]}],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call mc_getFilterChanges.

None

QUANTITY - A filter id.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_newBlockFilter","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc":  "2.0",
  "result": "0x244afc5c2cb35b24c5b91bba7f7ab19d" // 1
}

Creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call mc_getFilterChanges.

None

QUANTITY - A filter id.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_newPendingTransactionFilter","params":[],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc":  "2.0",
  "result": "0x1" // 1
}

Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren’t requested with mc_getFilterChanges for a period of time.

  1. QUANTITY - The filter id.
params: [
  "0xb" // 11
]

Boolean - true if the filter was successfully uninstalled, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_uninstallFilter","params":["0xb"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc": "2.0",
  "result": true
}

Polling method for a filter, which returns an array of logs which occurred since last poll.

  1. QUANTITY - the filter id.
params: [
  "0x16" // 22
]

Array - Array of log objects, or an empty array if nothing has changed since last poll.

  • For filters created with mc_newBlockFilter the return are block hashes (DATA, 32 Bytes), e.g. ["0x3454645634534..."].
  • For filters created with mc_newPendingTransactionFilter the return are transaction hashes (DATA, 32 Bytes), e.g. ["0x6345343454645..."].
  • For filters created with mc_newFilter logs are objects with following params:
  • removed: TAG - true when the log was removed, due to a chain reorganization. false if its a valid log.
  • logIndex: QUANTITY - integer of the log index position in the block. null when its pending log.
  • transactionIndex: QUANTITY - integer of the transactions index position log was created from. null when its pending log.
  • transactionHash: DATA, 32 Bytes - hash of the transactions this log was created from. null when its pending log.
  • blockHash: DATA, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log.
  • blockNumber: QUANTITY - the block number where this log was in. null when its pending. null when its pending log.
  • address: DATA, 20 Bytes - address from which this log originated.
  • data: DATA - contains one or more 32 Bytes non-indexed arguments of the log.
  • topics: Array of DATA - Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.)
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getFilterChanges","params":["0x16"],"id":101}' localhost:8545

// Result
{
  "id":101,
  "jsonrpc":"2.0",
  "result": [{
    "logIndex": "0x1", // 1
    "blockNumber":"0x1b4", // 436
    "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d",
    "transactionHash":  "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf",
    "transactionIndex": "0x0", // 0
    "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d",
    "data":"0x0000000000000000000000000000000000000000000000000000000000000000",
    "topics": ["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"]
    },{
      ...
    }]
}

Returns an array of all logs matching filter with given id.

  1. QUANTITY - The filter id.
params: [
  "0x16" // 22
]

See mc_getFilterChanges

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getFilterLogs","params":["0x16"],"id":101}' localhost:8545

Result see mc_getFilterChanges


Returns an array of all logs matching a given filter object.

  1. Object - the filter object, see mc_newFilter parameters.
params: [{
  "topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]
}]

See mc_getFilterChanges

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getLogs","params":[{"topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]}],"id":101}'

Result see mc_getFilterChanges


Returns the hash of the current block, the seedHash, and the boundary condition to be met (“target”).

none

Array - Array with the following properties: 1. DATA, 32 Bytes - current block header pow-hash 2. DATA, 32 Bytes - the seed hash used for the DAG. 3. DATA, 32 Bytes - the boundary condition (“target”), 2^256 / difficulty.

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"mc_getWork","params":[],"id":101}' localhost:8545

// Result
{
"jsonrpc":"2.0",
"id":101,
"result":["0x367ebe7ed77dde0a4cc134adaa769f93a833e08a86a0d38ab18e32cc3740b5f8","0x9b2baad7528ecec612c5751a6bd525905892d7892e155c3b05e61363154a940b","0x0000001dd67ebb66a2c0fc63b9907077f70b5315e1780a8b74f33d40e2a9a7e4"]
}

Used for submitting a proof-of-work solution.

  1. DATA, 8 Bytes - The nonce found (64 bits)
  2. DATA, 32 Bytes - The header’s pow-hash (256 bits)
  3. DATA, 32 Bytes - The mix digest (256 bits)
params: [
  "0x0000000000000001",
  "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "0xD1FE5700000000000000000000000000D1FE5700000000000000000000000000"
]

Boolean - returns true if the provided solution is valid, otherwise false.

// Request
curl -X POST --data '{"jsonrpc":"2.0", "method":"mc_submitWork", "params":["0x0000000000000001", "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "0xD1GE5700000000000000000000000000D1GE5700000000000000000000000000"],"id":101}'

// Result
{
  "id":101,
  "jsonrpc":"2.0",
  "result": true
}

Safe Storage of Backups

It is recommended that you store backups of both forms of your key (the Keystore / UTC file version and paper wallet version) in physically separate, offline environments.

This prevents loss of the private key & password due to: dead hard drive, lost USB drive, wet piece of paper, etc. Keep in mind that physical loss can affect an entire area (e.g. fire, flood).

Nobody can recover your key MoacWalletOnline is not a web wallet and cannot recover your private key or password, access your account, move funds, recover funds, nor cancel/reverse transactions.

We are a client-side interface that allows you to interact with the MOAC blockchain mainnet and testnet. Please secure & back up your key like the millions of dollars it could some day be worth.

SCS

The executable SCS node program was released on Pizza Day.

This release is alpha version of MOAC microchain. It is still under development but we want you to try and taste it with us. It is for programmers only.

The package is Only to run at a single node mode for easy debugging. It contains both vnode and scs executables and necessary files

Executables: Windows: pizzaAlpha.vnode.scs.widows.zip Ubuntu: pizzaAlpha.vnode.ubuntu.tar.gz, pizzaAlpha.scs.ubuntu.tar.gz

We also have some video instructions for developers. Please let us know your thoughts and comments.

English tutorials:

Youtube Youku

SubChainProtocolBase

启动 ./bin/moac –datadir “/tmp/moac/60/01” –networkid 1975 –nodiscover –verbosity 4

运行一个Vnode的控制窗 ./bin/moac attach /tmp/moac/60/01/moac.ipc

运行SCS1

./scs1/scsserver ./go/src/github.com/innowells/moac-scs/build/bin/scsserver

Start SCS2

.scs2/scsserver
./go/src/github.com/innowells/moac-scs/build/bin/scsserver

=============== Test commands in the console =============== personal.newAccount(“123456”) miner.start() personal.unlockAccount(mc.accounts[0], “123456”, 0) scs1=”0xA6D018ae6981552Df5C39b5911bF7CA793D0405c” scs2=”0x700A559b7C5c3D5f79df9f7EfdD0bd068CBFad4e” mc.getBalance(scs1)/1000000000000000000 mc.getBalance(scs2)/1000000000000000000 mc.getBalance(mc.accounts[0])/1000000000000000000

loadScript("deploy_p1.js")
loadScript("deploy_s1.js")
loadScript("test_s1.js")

sendtx(mc.accounts[0], scs1, 200)
sendtx(mc.accounts[0], scs2, 200)
mc.getBalance(scs1)/1000000000000000000
mc.getBalance(scs2)/1000000000000000000

registertopool(scs1)
registertopool(scs2)
subchainprotocolbase.scsCount()
subchainprotocolbase.scsList(scs1)
subchainprotocolbase.scsList(scs2)

miner.stop()
miner.start(1)
registeropen()
subchainbase.nodeCount()
registerclose()

General info

SubChainBase

SCS node selection

SCS creation

SCS running

SCS flushing

MOAC Pizza Alpha (Pangu 0.8.3 prerelease)

–Debian/Ubuntu/CentOS– This version only work with “–dev” option, not working with mainnet or testnet yet.

There are two tar files: pizzaAlpha.vnode.ubuntu.tar.gz. - vnode executables and files; pizzaAlpha.scs.ubuntu.tar.gz - three scs executables and files.

  1. Untar the file using tar, there are 4 directories:

    vnode
    scs1
    scs2
    scs3
    
  2. Start the vnode $ ./start_vnode.sh

    from another terminal, run moac again to attach the running node

    $ ./attach.sh
    

    Check and create coinbase account

    >personal.newAccount()
    

    from console prompt, start mining by running

    >miner.start(1)
    
  3. After vnode started, start scs servers. You need at least 2 scs servers to form the microchain.

    from another terminal, change into scs1/bin run the executable

    $./scs1
    

    do the same for the other two, if connected with vnode, some info should be seen as the following:

    ......
    INFO [05-23|01:21:56.111] 230:liveinfo: {1285}
    INFO [05-23|01:22:00.111] 221:liveinfo: {1286}
    INFO [05-23|01:22:05.112] 205:liveinfo: {1289}
    INFO [05-23|01:22:08.111] 206:liveinfo: {1290}
    INFO [05-23|01:22:09.120] 222:liveinfo: {1291}
    

    The number in {} is the vnode block number. All 3 scs should have the same info.

  4. scs servers need some initial funds to work. Currently there are fixed address for the test scs servers:

    scs1="0x027aee503f2e27fee5103df1796daeb6111e204d"
    scs2="0xba3597b4c20f0477c4ebe7cf81c565e556bd52f9"
    scs3="0x1675124b338671dd771a673c7d06606ae1cdd7b0"
    

    Otherwise you need to send some funds to the accounts. From prompt, load script

    >loadScript("mctest.js")
    >Send(mc.accounts[0], '', scs1, 0.1)
    >Send(mc.accounts[0], '', scs2, 0.1)
    >Send(mc.accounts[0], '', scs3, 0.1)
    
  5. Now start deploy the microchain from vnode:

    deploy_p1.js: protocol needed for microchain.
    deploy_s1.js: microchain contract.
    test_s1.js: test scripts for microchain.
    
    
    > personal.unlockAccount(mc.accounts[0])
    true
    > loadScript("deploy_p1.js")
    null [object Object]
    

    Testnet deploy:

    Contract mined! address: 0xeaf8f52588af16aebb26c4ca8fb10d5e0b8b1d70 transactionHash: 0xf029d6168c289fac8322bb1925205c905f31a4cc45dc826f4e3b7200ceda3de5
    
  6. Load the subchain script file:

    > loadScript("deploy_s1.js")
    null [object Object]
    true
    Contract mined! address: 0x78934339dcb0642bdfd2afb3e028ee40be809280 transactionHash: 0x503fb3377866071a80e4f023c2cab4999876b93fbaa86dec54d73b1d4d8391a7
    
  7. Load the test script.

    > loadScript("test_s1.js")
            true
    
  8. Register scs servers in the pool:

    > registertopool(scs1)
    sending from:0xa8863fc8ce3816411378685223c03daae9770ebb to:0x08b95aebd9c3cfbea68631486cc76d7281c15a79 amount:12 with data:0x4420e486000000000000000000000000a4e1e48c7b2b0bd7b2f202e0db0270a9678df266
    undefined
    > registertopool(scs2)
    sending from:0xa8863fc8ce3816411378685223c03daae9770ebb to:0x2287b6c3643aa1d96ca5eb198f660c512bef28d1 amount:12 with data:0x4420e486000000000000000000000000f1f5b7a35dff6400af7ab3ea54e4e637059ef909
    undefined
    

    You can see if the node is registered:

    > subchainprotocolbase.scsCount()
        2
    

    For safety issues, scs servers need to wait for some blocks after register in the pool. You can find the info about a scs server by:

    > subchainprotocolbase.scsList(scs1)
    ["0xecd1e094ee13d0b47b72f5c940c17bd0c7630326", 12000000000000000000, 942, 1.15792089237316195423570985008687907853269984665640564039457584007913129639935e+77]
    

    The number ‘942’ is the block number this scs server can join microchain, usually this is 50 blocks later after the scs registered in the pool.

  9. Open subchain for scs to join:

When there are more than 2 scs in the pool, you can start open the microchain for scs server to join You may need to unlock the mc.accounts[0] for this step.

> personal.unlockAccount(mc.accounts[0])
true
> registeropen()
miner.starsending from:0xa8863fc8ce3816411378685223c03daae9770ebb to:0x26c27eb5585d1e978d4da14f0eb2ee479d733a46 amount:0 with data:0x5defc56c
undefined

There will be some confirmation tx send from vnode to scs servers. You can also check to see how many scs servers are selected in the microchain:

    > subchainbase.nodeCount()
    2

When you have enough scs servers, you can close registration and start the microchain:

    > registerclose()
    sending from:0xa8863fc8ce3816411378685223c03daae9770ebb to:0xc3c6e85820d97477172498ce7aed37b0bb22e67e amount:0 with data:0x69f3576f
  1. Subchain mining started: After these steps, scs server should have some info like:

    INFO [05-23|01:23:01.754] 278:Commit new mining work   number=2 txs=0 elapsed=490.027µs
    INFO [05-23|01:23:01.755] 278:🔨 mined potential block    number=2 hash=0xa67b93923ba3ea9ff43f076c5839aa5ea31291c7cf71db1c80c18af2c1b9be1b
    INFO [05-23|01:23:11.781] 280:
    ###### BLOCK Number: 3 ######
    block.Hash:       0xe0a8c81c8f3898721ea99cd569f0fc545af03ffb18679171cb2eaf79ec6ee672
    block.ParentHash: 0xa67b93923ba3ea9ff43f076c5839aa5ea31291c7cf71db1c80c18af2c1b9be1b
    SubchainAddr:     0xa107434b94c8c2690dbcff298434b91d22f767db
    ##############################
    
    INFO [05-23|01:23:14.112] 208:liveinfo: {1321}
    

MOAC release

Download from latest release version of VNOE from release link

Debian/Ubuntu/CentOS

  1. Untar the file using tar, under the directory, run ./moac

To see the help, use ./moac –help

To enable the console, run: ./moac console

A mainnet directory will be created under $HOME/.moac/ and some info should be seen as:

INFO [04-24|11:24:26.506] 86161:IPC endpoint closed: /home/user/.moac/moac.ipc

from another terminal, run moac again to attach the running node

./moac attach

or

./moac attach $HOME/.moac/moac.ipc
  1. from console prompt, create coinbase account

    >personal.newAccount()
    
  2. from console prompt, start mining by running

    >miner.start()
    
  3. from another terminal, run moac again to attach the running node

    ./moac attach
    
  4. from prompt, load script

    >loadScript("mctest.js")
    
  5. check if miner has mined any moac by checking:

    >mc.accounts
    
  6. create another account

    >personal.newAccount()
    
  7. try send from one account to another:

    >Send(mc.accounts[0], '', mc.accounts[1], 0.1)
    

WINDOWS

Unzip the file to a directory, under the directory, run

2.1 查看moac帮助

打开命令(cmd)终端,转到墨客解压目录,在命令行中执行:

D:\moacPangu0.8.2-win>moac --help

显示帮助信息,包含但不限于以下内容:

查看moac帮助

打开命令(cmd)终端,转到墨客解压目录,在命令行中执行:

D:\ moacPangu0.8.2-win>moac --help

显示帮助信息,包含但不限于以下内容:

Start MOAC.... 2
NAME:
 moac - the MOAC-core command line interface
 Copyright 2017 The MOAC Authors
USAGE:
 moac [options] command [command options] [arguments...]
VERSION:
 0.8.2-develop-ed4070bf
MOAC CORE OPTIONS:
--config value                      TOML configuration file
--datadir "C:\Users\[userName]\AppData\Roaming\MoacNode" Data directory for the databases and keystore
--keystore                         Directory for the keystore (default = inside the datadir)
--nousb                           Disables monitoring for and managing USB hardware wallets
--networkid value                   Network identifier (integer, 1=Pangu, 2=Testnet) (default: 1)
--testnet                          MOAC test network: pre-configured proof-of-work test network
2.2 运行节点

打开命令(cmd)终端,转到墨客当前目录,在命令行中执行:

D:\ moacPangu0.8.2-win>moac

显示如下信息:

moac\_install\_win\_0

moac_install_win_0

至最后三行显示如下:

INFO [04-01|20:44:42.851] 1:[node/node.go->Node.startIPC]
INFO [04-01|20:44:42.852] 145:IPC endpoint opened: \\.\pipe\moac.ipc
INFO [04-01|20:45:12.846] 152:Block synchronisation started

表示节点安装成功,如果网络正常,就开始同步区块。

系统将MOAC节点默认安装在目录:

C:\Users\[userName]\AppData\Roaming\MoacNode\

该目录下包含两个文件夹:moac和keystore。

2.3 进入MOAC console界面

系统关机或主动关闭运行中的节点后,如果需要重新启动节点,在命令行中执行:

D:\ moacPangu0.8.2-win>moac console

之后一直滚屏以同步区块数据。

打开另一个命令(cmd)终端,转到墨客当前目录,在命令行中执行:

D:\ moacPangu0.8.2-win>moac attach
moac\_install\_win\_1

moac_install_win_1

该命令行不会主动滚屏,而是等待命令。

3. 挖矿

3.1 建立新账户

挖矿前必须建立一个自己的账户。

进入MOAC console界面,执行命令:

> personal.newAccount()

系统会提示输入一个密码,例如”passwd”,并再次输入相同密码确认后,会显示一个以0x开头的字符串,即为MOAC帐号的公开地址。

moac\_install\_win\_2

moac_install_win_2

系统同时会在以下目录:

C:\Users\[userName]\AppData\Roaming\MoacNode\testnet\keystore

记录一个账号文件。请保存好该文件,并牢记密码,之后用于解密帐号和操作。

3.2 查看账户

进入MOAC console界面,执行命令:

> mc.accounts

可以查看本节点下的所有账号。

3.3 查看账户余额

进入MOAC console界面,执行命令:

> mc.getBalance(mc.accounts[0])

可以查看本节点下的账号余额。0表示第一个账户,也是默认挖矿账户。

或者:导入“mctest.js”的情况下(见4.1),执行命令:

> checkBalance()

该命令用于查看当前节点所有账号的余额。

3.4 查看挖矿状态

进入MOAC console界面,执行命令:

> mc.mining

返回true表明节点正在挖矿,false表明节点没有挖矿。

3.5 开始挖矿

进入MOAC console界面,执行命令:

> miner.start()

挖矿状态下,数据显示有明显不同。

moac\_install\_win\_4

moac_install_win_4

挖到矿之后,可以查看余额

moac\_install\_win\_5

moac_install_win_5

登录墨客区块链浏览器页面: http://explorer.moac.io

moac\_explorer\_0

moac_explorer_0

在搜索栏输入你的挖矿账号地址,会显示该账号的余额等信息。

moac\_explorer\_1

moac_explorer_1

在搜索栏输入你挖到矿的区块号,会显示该区块的信息。

Miner正是你的账号地址。

moac\_explorer\_2

moac_explorer_2

3.6 停止挖矿

进入MOAC console界面,执行命令:

> miner.stop()

4. 交易

4.1 读入测试函数

部分功能程序存储在mctest.js里。

进入MOAC console界面,执行命令:

> loadScript("mctest.js")
4.2 交易条件

为执行交易,需要至少两个帐号,其中一个有足够的mc。

如果没有目标账号,可以用步骤2.3.1的命令创建一个本地账号。并用命令:

> mc.accounts

显示当前节点中存储的账号,应该至少有一个挖矿账号。

4.3 交易

进入MOAC console界面,执行命令:

> Send(mc.accounts[0], 'passwd', mc.accounts[1], 0.1)

这个过程需要第一个账号的密码。比如’passwd’,发送额为0.1 mc。

moac\_install\_win\_6

moac_install_win_6

在系统挖矿的情况下,发送应该在下一个区块产生时完成。

系统显示的是以 sha(Sand) 为单位的余额, 1 mc = 1e18 sha。

TokenPocket钱包

https://github.com/MOACChain/moac-core

点击进入上面网址后,点击wallets进入。  |token\_pocket\_entry|

TokenPocket 是一款移动端轻钱包APP,它旨在为普通用户提供一款安全放心、简单好用、功能强大的数字资产钱包应用,使用起来非常流畅,也符合国内用户的使用习惯,全中文界面,适合新手使用。

另外这款钱包整合了多体系数字资产可供选择和存放(多资产钱包,目前暂支持以太坊底层和井通底层发行的Token,后续逐渐添加更多底层。),未来还可以支持在钱包中进行跨链交易(真正的跨链原子交易),最大程度的便利了用户对数字资产的保存和流通。

TokenPocket使用图文教程开始

这里以安卓版本的TokenPocket为例:

首次安装好以后打开,点APP进入登录界面会有相关系统权限提示,点击始终允许即可:(极个别的无法创建和导入钱包的就是因为权限设置这里的问题,具体的可以到设置–应用里面去找到TokenPocket去设置权限)

一、TokenPocket 创建钱包

|token\_pocket\_create\_wallet|

创建钱包

钱包体系:创建钱包,需要选择钱包体系,当前暂支持以太坊体系和井通体系,后续还会添加比特币体系、EOS等体系,这里以以太坊体系为例。

钱包名称:输入自己喜欢的名字即可;

设置密码:密码这里没有做硬性要求,但是建议数字+字母,字母大写小写搭配等方式,至少输入8位,会在你做转账等敏感操作的时候要求输入,务必牢记。

提示信息:可以输入一些相关的提示词等(可不填)。

服务条款:只有勾选才可以成功的创建钱包,服务及隐私条款可点击进行详情查看。

以上要素填写完毕以后,点击创建钱包即可完成以太坊体系钱包的注册。

二、TokenPocket 备份助记词

助记词实际上就是明文私钥的一种表达形式,可以等同于私钥,好处是用12个单词代替一大串0,1二进制数私钥,方便记忆和备份(此处强烈建议抄在纸上保存好,不要用网络存储,最好再找个地方保存起来),恢复钱包时最便捷,只需要导入助记词就好。

坏处就是一旦丢失和私钥丢失一样,谁知道了你的助记词就等于知道私钥,就等于你的地址里的币存在丢失的可能,并且永远找不回来,所以网络上凡是需要填写私钥和助记词的地方都要慎重再慎重。

|token\_pocket\_backup\_wallet|

备份钱包(助记词备份),可以防止你的钱包丢失,这个过程务必要完成,否则钱包无法使用,即使退出app重新登录后还会提示进行备份。

点击备份钱包,记录下弹出的界面中12组英文单词,记录到你的实体本子上面,并妥善保管好。具体如下图所示:

|token\_pocket\_backup\_mnemonic|

记录完毕后点击下一步,从界面中按照正确的顺序来搭配正确的12组英文单词。

三、TokenPocket 添加新资产

在资产一栏,点右上角的加号,点击添加资产,会看到添加资产的界面,可以快速的根据体系来进行Token的添加和删除

|token\_pocket\_add\_asset|

四、TokenPocket 导入钱包

1、点击初始界面中的导入钱包,如下图所示:

|token\_pocket\_import\_wallet|

选择体系

2、点击需要导入的钱包类型,这里以以太坊体系为例,点击以太坊弹出如下界面:

|token\_pocket\_select\_asset|

助记词导入

3、钱包导入类型分为:助记词和私钥,这里先来演示助记词的钱包导入方法,在置顶的输入框中正确输入12组英文单词以后(空格分隔),还需要填写相关项方可正确添加钱包。

选择格式:这里按照系统给出的默认值即可;

钱包名字:这里可以选择自己喜欢的名字进行设置,跟原钱包(例如imtoken之前的钱包名称不要求一致,个人自由设置即可。)

钱包密码:重新设置自己易记的密码即可,要求8位以上;

提示信息:可以输入一些相关的提示词等(可不填)。

勾选同意服务及隐私条款后点击开始导入。

4、私钥导入是指,利用创建钱包以后备份的明文私钥进行钱包导入,再导入的时候要注意私钥大小写的区分,如果出现错误就耐心进行检查,直到正确输入为止,私钥导入如下所示:

|token\_pocket\_import\_private\_key|

私钥导入

在置顶的输入框中输入明文私钥

钱包名字:这里可以选择自己喜欢的名字进行设置,跟原钱包(例如imtoken之前的钱包名称不要求一致,个人自由设置即可。)

钱包密码:重新设置自己易记的密码即可,要求8位以上;

提示信息:可以输入一些相关的提示词等(可不填)。

勾选同意服务及隐私条款后点击开始导入。

五、TokenPocket 私钥备份

助记词和私钥对于钱包来说同等重要,基本上可以理解为:助记词=密钥=keystore+密码,由于keystore只有在以太网页钱包中才有导出备份功能,所以这里不做过多演示。

点击钱包主界面中的我,会弹出如下界面:点击管理钱包,弹出如下界面:这里可以看到已经创建过的钱包,点击我们需要备份私钥的钱包,会提示输入密码提示框,正确的输入密码之后,弹出如下界面:

|token\_pocket\_backup\_private\_key|

为了安全起见,此明文私钥最好也记录到本子上妥善保管。

墨客版本介绍 (Versions)

1.盘古 (Pangu)

内部版本识别号 (Version):0.8

Release Date: 3/31/2018

Major Progress:v-node module,SCS (POS) module,chain3 lib,wallet, Mist, explorer

Available feature: * v-node mining * SCS mining * Sharding * System contract for auto trigger, hash lock * Subchain Protocol contract for SCS miner registration * Subchain contract for Dapp configuration and flush control * wallet

Documents:

2.女娲(Nuwa)

内部版本识别号(Version):1.0

Release Date: 6/30/2018 Major Progress:Distributed File System service, Cross-chain Service Available feature: * Cross subchain * Cross exteral chain * Persistant File system * IPFS mining Documents:

3.伏羲(Fuxi)

内部版本识别号(Version):1.1

Release Date: 12/30/2018 Major Progress:Generalized Subchain Contract Processing, multicast routing protocol for SCS layer Available feature: * Support any applications running in SCS (JAVA, c++,etc) * Subchain service market * SCS layer secure and decentralized communication * IOT mining * Data encryption Documents:

4. 神农(Shennong)

内部版本识别号(Version):1.2

Release Date: 6/30/2019 Major Progress:v-node consensus protocol upgrade Available feature: * High performance (>10k TPS) * Zero knowledge support * Data store/exchange market Documents:

环境安装

nodejs安装

https://nodejs.org/

下载nodejs安装即可, node -v查看安装的版本,npm -v 查看npm版本。 建议对nodejs进行简单的环境配置, 同时下载并安装git, 并通过git –version查看git版本。

进行chain3库安装

npm install chain3 -g

注意:某些情况下,Windows下需要用“以管理员身份运行”进入cmd界面,才能使用npm
install 命令

API使用准备

var Chain3 = require('chain3');
var chain3 = new Chain3();
chain3.setProvider(new chain3.providers.HttpProvider('http://xxx.xxx.xxx.xxx:xxxx'));

API介绍

  1. chain3.version.network:查看当前MOAC网络ID
var networkId = chain3.version.network;
console.log('network id:'+ networkId);
  1. chain3.setProvider: 设置API访问MOAC节点方式
chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545'));
  1. chain3.sha3(string,options)

参数:string:传入的需要使用Keccak-256 SHA3算法进行哈希运算的字符串 options:可选项,如果要解析的是hex格式的十六进制字符串,需要设置为hex

var hash = chain3.sha3("the string to be hashed");
console.log(hash);
var hashOfHash = chain3.sha3(hash,{encoding:'hex'});
console.log(hashOfHash);
  1. chain3.net.peerCount: 返回连接节点已连上的其他moac节点的数量
var peerCount = chain3.net.peerCount;
console.log(peerCount);
  1. chain3.net.listening: 返回连接节点的listen状态
var listenState = chain3.net.listening;
console.log(listenState);
  1. chain3.mc.coinbase: 节点配置的,如果挖矿成功奖励发送到该地址
var nodeCoinbase = chain3.mc.coinbase;
console.log(nodeCoinbase);
  1. chain3.mc.mining: 节点的挖矿状态
var miningState = chain3.mc.mining;
console.log(miningState);  //true or false
  1. chain3.mc.accounts: 节点持有的账户列表
var nodeAccounts = chain3.mc.accounts;
console.log(nodeAccounts);
  1. chain3.mc.blockNumber: 当前区块号
var nowBlockNumber = chain3.mc.blockNumber;
console.log(nowBlockNumber);
  1. chain3.mc.getBlockTransactionCount: 指定区块的交易数量
var transactionCount = chain3.mc.getBlockTransactionCount(96160);
console.log(transactionCount);
  1. chain3.mc.getBalance: 给定地址的余额
var balance = chain3.mc.getBalance("0x36eaa71d7383be53cb600743aad08a55222a4915");
console.log("getBalance1" + balance); //instanceof BigNumber
console.log("getBalance2" + balance.toString(10));
//输出结果: getBalance1:3.04527226722e+21
//         getBalance2:3045272267220000000000
  1. chain3.mc.defaultBlock: 默认块设置
var defultBlock = chain3.mc.defaultBlock;
console.log("defaultBlock" + defultBlock);
//默认值是latest,即最近刚出的区块
chain3.mc.defaultBlock = 123;  //传入一个值来覆盖默认配置
console.log("defaultBlock" + defultBlock);
  1. chain3.mc.gasPrice: 当前gas价格
var gasPrice = chain3.mc.gasPrice;//该值由最近几个块的gas价格的中值决定
console.log(gasPrice.toString(10));
  1. chain3.mc.estimateGas: 执行一个消息调用或交易,返回使用的gas量
var result = chain3.mc.estimateGas({
 to :"0xf7ebc6b854a202efe08e91422a44ba2161ed50dc",
 data: '0x23455654'
    //gas: 11,          //可选参数,设定gas
    //gasPrice: 11      //可选参数,设定gasPrice
});
console.log('estimateGas  :'+ result);
//输出结果:gasprice :20000000000
//        estimateGas :1273
  1. chain3.mc.getCode: 获取指定地址的代码(地址合约编译后的字节代码)
var code  = chain3.mc.getCode("0x0000000000000000000000000000000000000065");//contract address
  1. chain3.mc.syncing: 如果正在同步,返回同步对象;否则返回false
var sync = chain3.mc.syncing;
console.log('syncing  :'+ sync );
//如果正在同步,返回同步开始区块号、节点当前正在同步的区块号、预估要同步到的区块号
  1. chain3.mc.getTransaction: 返回指定交易哈希值的交易
var blockHash = "0xbeca9c6a3a2f7bde119193e802f9506cc0ae58f23aca59f7ac8bf98e4e2242b5";
var transaction = chain3.mc.getTransaction(blockHash);
console.log('get transaction:'+ JSON.stringify(transaction));
  1. chain3.mc.getBlock: 返回区块号或区块哈希值所对应的区块
var getTheBlock = chain3.mc.getBlock(96190);
console.log('get the block  :'+ JSON.stringify(getTheBlock ));

//TODO 稍后更新

基本指令

–testnet: 连接到MOAC测试网络;

–rpc: 启用HTTP的RPC服务,以便非本机访问该MOAC节点服务;

–rpcaddr value: 默认是”localhost”, 只能本机访问; 可通过设置 为”0.0.0.0”, 以便非本机访问该MOAC节点服务, 但现在RPC服务是基于HTTP的,是明文传输,需注意安全问题;

–rpcport value: 默认是”8545”, 一般来说不用改,用默认端口即可;

–rpcapi value: 指定RPC要开放的API服务,默认为”chain3,mc,net”,常用的一般还会配置比如personal,admin,debug,miner,txpool,db,shh等,但是因为RPC服务是明文传输,所以,如果使用personal的时候,要注意安全问题;

–rpccorsdomain value: 一般来说,如果你知道要用这个选项的时候,使用”*”值即可,更详细可自行搜索“CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)”中相关关键词进一步了解;

–jspath loadScript: 默认值为”.”, loadScript装载javascript文件的主目录;

示例如下:

./moac attach /xx/xxx/moac.ipc 通过本地ipc接口连接到MOAC节点

./moac attach http://xxx.xxx.xxx.xxx:8545 通过基于HTTP的RPC接口连接到本地或者远程MOAC节点

./moac –testnet 启动MOAC测试节点

./moac –testnet console 启动MOAC测试节点,并启动交互命令行

./moac –testnet –rpc 启动MOAC测试节点,同时启动RPC服务

./moac –testnet –rpc –rpcaddr=0.0.0.0 –rpcapi=”db,mc,net,chain3,personal,debug” –rpccorsdomain=”*” 启动MOAC测试节点,非本机可访问,非本机也可以使用personal及debug服务,同时提供跨域资源共享服务;

子链协议合约

【功能简介】

子链协议合约定义了用于上层的共识协议。子链的共识协议可以分为多种

  1. 处理类共识协议(类似于CPU),比如POS,POW,PBFT等
  2. 文件存储类共识协议(类似于硬盘),比如POF(IPFS),FileCoin等
  3. 功能类共识协议,比如随机数,时戳等
  4. 自定义类共识协议,比如投票,IOT,sensor network等

子链协议合约部署之后,可以让具有对应模块的SCS注册,并缴纳保证金。在等待时间之后(通常是50个block),就成为子链的候选SCS节点。

子链协议合约必须与对应的SCS模块协同工作。墨客提供一个POS的实现,包括SubchainProtocolBase.sol 和相应的SCS模块。

【功能模块】

  • 1.SCSList,存储所有注册并缴纳保证金的节点
  • 2.bondMin,参与这个协议所需最低保证金
  • 3.register(注册):具有相应模块的SCS调用注册,并缴纳保证金
  • 4.withdraw(退出):SCS可以选择退出,并在一定时间后返回保证金
  • 5.getSelectionTarget:根据子链要求的SCS数得到选择标准,即如何从总数中随机取出需要的SCS节点数
  • 6.approveBond(子链押金授权):授权SCS参与的子链可以在SCS表现恶意的时候没收保证金
  • 7.forfeitBond(没收押金):子链没收SCS的押金

子链创建过程

【前提条件】

子链协议合约已经创建

【参数】 * 1.所采用的协议 * 2.子链的SCS个数[min,max],选择总节点数的千分比 * 3.子链刷新周期 * 4.子链逻辑代码Funccode

【流程】 * 1.DAPP部署者在v-node端部署一个全局的子链合约,设置Funccode * 2.DAPP部署者调用RegisterOpen,允许SCS进来注册。同时调用V-node代码,如果检测到相连的scs符合要求,向scs推送一个enroll 的message * 3.SCS节点发起一个对子链合约的RegisterAsSCS的调用,来确认参与这个子链 * 4.DAPP部署者调用RegisterClose,关闭注册, V-node在执行时,判断条件是否满足。如果满足,v-node向scs推送一个newSubchain msg。SCS端触发一系列的初始化操作,完成subchain的设置。如果条件不满足,DAPP部署者重新发起这个过程。

常用功能介绍

智能合约介绍

智能合约开发

子链部署介绍

TODO

北京时间2018年4月30日22:00,MOAC公链正式上线。

以下为MOAC Windows版系统安装及挖矿教程。

1. 准备工作

从MOAC官网http://moac.io 或者 https://github.com/MOACChain/moac-core/ 下载Windows版本的系统软件包。

MOAC官网提供两种版本下载,MOAC-Pangu-0.8.2-Ubuntu.zip和MOAC-Pangu-0.8.2-Windows.zip。 其中Pangu(盘古)为代号,0.8.2为版本号。

该版本适用于Windows 7及以上系统。本文实际操作环境为:64位Windows 10 中文版。

2. 产生本地MOAC节点

解压MOAC-Pangu-0.8.2-Windows.zip到本地硬盘。

2.1 查看moac帮助

打开命令(cmd)终端,转到墨客解压目录,在命令行中执行:

D:\moacPangu0.8.2-win>moac --help

显示帮助信息,包含但不限于以下内容:

查看moac帮助

打开命令(cmd)终端,转到墨客解压目录,在命令行中执行:

D:\ moacPangu0.8.2-win>moac --help

显示帮助信息,包含但不限于以下内容:

Start MOAC.... 2
NAME:
 moac - the MOAC-core command line interface
 Copyright 2017 The MOAC Authors
USAGE:
 moac [options] command [command options] [arguments...]
VERSION:
 0.8.2-develop-ed4070bf
MOAC CORE OPTIONS:
--config value                      TOML configuration file
--datadir "C:\Users\[userName]\AppData\Roaming\MoacNode" Data directory for the databases and keystore
--keystore                         Directory for the keystore (default = inside the datadir)
--nousb                           Disables monitoring for and managing USB hardware wallets
--networkid value                   Network identifier (integer, 1=Pangu, 2=Testnet) (default: 1)
--testnet                          MOAC test network: pre-configured proof-of-work test network

2.2 运行节点

打开命令(cmd)终端,转到墨客当前目录,在命令行中执行:

D:\ moacPangu0.8.2-win>moac

显示如下信息:

moac\_install\_win\_0

moac_install_win_0

至最后三行显示如下:

INFO [04-01|20:44:42.851] 1:[node/node.go->Node.startIPC]
INFO [04-01|20:44:42.852] 145:IPC endpoint opened: \\.\pipe\moac.ipc
INFO [04-01|20:45:12.846] 152:Block synchronisation started

表示节点安装成功,如果网络正常,就开始同步区块。

系统将MOAC节点默认安装在目录:

C:\Users\[userName]\AppData\Roaming\MoacNode\

该目录下包含两个文件夹:moac和keystore。

2.3 进入MOAC console界面

系统关机或主动关闭运行中的节点后,如果需要重新启动节点,在命令行中执行:

D:\ moacPangu0.8.2-win>moac console

之后一直滚屏以同步区块数据。

打开另一个命令(cmd)终端,转到墨客当前目录,在命令行中执行:

D:\ moacPangu0.8.2-win>moac attach
moac\_install\_win\_1

moac_install_win_1

该命令行不会主动滚屏,而是等待命令。

3. 挖矿

3.1 建立新账户

挖矿前必须建立一个自己的账户。

进入MOAC console界面,执行命令:

> personal.newAccount()

系统会提示输入一个密码,例如”passwd”,并再次输入相同密码确认后,会显示一个以0x开头的字符串,即为MOAC帐号的公开地址。

moac\_install\_win\_2

moac_install_win_2

系统同时会在以下目录:

C:\Users\[userName]\AppData\Roaming\MoacNode\testnet\keystore

记录一个账号文件。请保存好该文件,并牢记密码,之后用于解密帐号和操作。

3.2 查看账户

进入MOAC console界面,执行命令:

> mc.accounts

可以查看本节点下的所有账号。

3.3 查看账户余额

进入MOAC console界面,执行命令:

> mc.getBalance(mc.accounts[0])

可以查看本节点下的账号余额。0表示第一个账户,也是默认挖矿账户。

或者:导入“mctest.js”的情况下(见4.1),执行命令:

> checkBalance()

该命令用于查看当前节点所有账号的余额。

3.4 查看挖矿状态

进入MOAC console界面,执行命令:

> mc.mining

返回true表明节点正在挖矿,false表明节点没有挖矿。

3.5 开始挖矿

进入MOAC console界面,执行命令:

> miner.start()

挖矿状态下,数据显示有明显不同。

moac\_install\_win\_4

moac_install_win_4

挖到矿之后,可以查看余额

moac\_install\_win\_5

moac_install_win_5

登录墨客区块链浏览器页面: http://explorer.moac.io

moac\_explorer\_0

moac_explorer_0

在搜索栏输入你的挖矿账号地址,会显示该账号的余额等信息。

moac\_explorer\_1

moac_explorer_1

在搜索栏输入你挖到矿的区块号,会显示该区块的信息。

Miner正是你的账号地址。

moac\_explorer\_2

moac_explorer_2

3.6 停止挖矿

进入MOAC console界面,执行命令:

> miner.stop()

4. 交易

4.1 读入测试函数

部分功能程序存储在mctest.js里。

进入MOAC console界面,执行命令:

> loadScript("mctest.js")

4.2 交易条件

为执行交易,需要至少两个帐号,其中一个有足够的mc。

如果没有目标账号,可以用步骤2.3.1的命令创建一个本地账号。并用命令:

> mc.accounts

显示当前节点中存储的账号,应该至少有一个挖矿账号。

4.3 交易

进入MOAC console界面,执行命令:

> Send(mc.accounts[0], 'passwd', mc.accounts[1], 0.1)

这个过程需要第一个账号的密码。比如’passwd’,发送额为0.1 mc。

moac\_install\_win\_6

moac_install_win_6

在系统挖矿的情况下,发送应该在下一个区块产生时完成。

系统显示的是以 sha(Sand) 为单位的余额, 1 mc = 1e18 sha。

1. 区块链技术的痛点

以下以区块链应用的主要平台以太坊为例,表述现有区块链技术的缺陷和痛点。

1.1 处理能力很低,可扩展性比较差

以太坊目前能够支持的TPS非常有限,大概15-30 TPS。所有的节点都处理同样的智能合约,而且所有合约的状态都记录到公共的区块链账本中。这样的系统难以支持成千上万的DAPP的调用和状态存储,一两个受欢迎的应用就可以把以太坊堵死。

1.2 以太坊不是为DAPP所设计的

从中本聪的比特币开始,区块链技术的主要目的是建立一个去中心化的电子货币系统。以太坊在此基础上发展而来,增加了智能合约的功能,但是并没有改变这个本质。以太坊的架构很多方面不适合DAPP。表现在几个方面:

  1. DAPP的用户的学习曲线非常陡峭

如果用户需要使用一个基于智能合约的DAPP,他必须先做这么几件事情,第一,他要获得一个钱包地址,私钥,并知道如何正确的使用钱包地址和保存私钥;第二,他必须通过某种方式获得eth。通常的做法是支付昂贵的手续费之后购买一些eth。之后需要等待多日,才可以将购买的eth转移到DAPP的钱包地址。这个过程对区块链的小白来说非常复杂,而且需要等待足够长的时间(大于一周)才能完成,之后才能真正的使用DAPP。

  1. 维护DAPP运行的成本不公平的偏向于DAPP的用户

DAPP的创建者部署了合约之后,合约就可以一直运行下去。DAPP的创建者/维护者不再需要为系统的维护支付任何费用。而是把消耗系统资源的成本转嫁到了DAPP的用户,一次部署,无限使用。

  1. 不利于构建DAPP的生态。DAPP创建者的主要目的是让更多的用户使用该DAPP,比较小的部署成本和巨大的使用成本,并不是DAPP创建者所真正需要的。基于区块链的DAPP的使用应该跟传统的APP一样,用户从APP store下载了之后就可以立刻免费或者以很低的成本使用APP。用户其实不需要关心底层的区块链是什么样的。他根本不需要关心Eth的存在或者如何获得Eth。

1.3 token主要分配方式是通过挖矿

中本聪的理想是每个拥有计算机和网络的人都可以参与挖矿,并获得虚拟货币。这样,使得比特币的分配可以更加去中心化,让更多的人可以使用比特币。但现实是挖矿已经变得非常昂贵,只有支付得起巨额的矿机和昂贵电力的人才能在这个分配过程中受益。以太坊的挖矿采用GPU,比比特币的ASIC相对好一点,但是依然很昂贵。虽然以太坊尝试转换到POS的共识机制,但是那样仍然维持了强者恒强、富者愈富的场景。以太坊及其他大多数区块链缺乏有效的二次分配token的方式来去中心化。

2. MOAC的方案

墨客区块链(MOAC)通过对以太坊系统架构的革新能够同时解决上面的三个问题,并提供有效的跨链功能。具体的做法如下:

2.1 分层

2.1.1 采用分层结构实现分片

将balance transfer和智能合约分开处理,底层以POW的方式处理所有的balance transfer和全局合约,解决全局一致性和双花的问题。DAPP的智能合约部署在上层,采用分片技术,通过POS或者PBFT的方式实现子片的数据一致性,提高系统TPS至100倍。

墨客的底层节点称为v-node,采用POW挖矿方式。

墨客引入智能合约服务(Smart Contract Server,scs)节点用于处理合约。

通过分层处理,合约在逻辑子链中执行,不会影响到正常用户的交易处理。

每个部署的DAPP合约可以自己选择所需的scs数量及共识方式,有自己的子链来保存状态。子链采用定期刷新的机制将自己状态的hash写入底层区块链,以实现一致性。

2.1.2 费用分担

DAPP的创建者必须支付子链中每个区块的费用,类似以每月支付水电账单的方式维持DAPP的持续运行。

DAPP的使用者可以采用直接调用的方式,不需要支付任何gas费用,对DAPP的应用发起调用。如果需要防止用户滥用,DAPP自己可以实现相应的处理方式。

这样,上层的共识协议不需要消耗大量的能源来获得随机数,而是纯粹处理智能合约的执行或者服务,对系统的要求非常低。普通的嵌入式系统甚至手机都可以参与。节点数量增加,然后通过分片的方式支持成千上万的DAPP运行;反过来,DAPP持续的支付费用可以支持更多的上层矿工。这样就形成了一个开放的,正反馈的循环,使得墨客系统成为一个巨大的,适合DAPP的生态圈。

2.2 分片(sharding)

分片是指将网络中的所有节点分成若干个子群体,这些子群体之间通过预定义的方法执行原来所有节点都要处理的工作,从而达到提高系统处理能力的结果。

以太坊目前的分片策略是在一个周期内,将所有的节点分成若干份,然后将合约分配给每个分片。当周期结束时,会重新分片。这里会有几个问题:

  1. 需要一个全局的存储器来保存这个分片信息。
  2. 这个周期通常比较长,如果节点数动态变化比较大的话,分片的信息会很容易过时。
  3. 周期结束时,当前分片处理的合约必须重新分配到新的分片,造成不必要的切换资源操作。
  4. 分片的共识方式与底层的共识一样,这样分片的功能必须等主网切换到POS才能采用。

墨客采用分层的办法来实现分片。

墨客的底层采用POW的方式保证所有的数据的一致性。

分片处理的节点称为SCS,其特点包括:

  1. 每个分片有自己的存储,就是子链。
  2. SCS可以有不同于底层的共识方式,比如pos,pbft。
  3. SCS的区块生成时间可以与底层不一致,比如可以采用快速的区块周期来进一步提高处理速度。
  4. SCS周期性的向底层flush结果,从而获得阶段性的全局一致性。

与以太坊分片方法不同,墨客分片采用合约驱动的模式。就是说一个合约对应于一个系统分片。合约创建时自动随机选择相应数量的节点形成一个分片来处理这个合约。这个合约的生存周期包括从创建到结束合约都在这个分片中实现。当然,中间如果需要,可以重新洗牌来选择新的分片节点。

墨客系统提供一个Pos分片实现。用户也可以实现自己的共识协议,作为SCS的一个插件。这样就形成了子链的概念。

合约的执行尽可能都在SCS端执行。V-node只处理支付交易和必要的合约调用。如此可以降低支付交易的gas量,进一步提高处理能力,而不会造成系统太大的负担。

整个系统的处理速度上去之后,会对v-node的要求更高。体现在两个方面,一个是网络的带宽,另一个是存储的容量。当然还有每个节点的GPU运算能力。随着光纤网络和5G网络的普及,带宽预计不会成为一个瓶颈。存储器的价格则更加不是问题。对于普通用户而言,因为有SCS可以参与挖矿,并不一定需要部署一个v-node,只要有信任的v-node可以连就可以。这样墨客系统会形成两个层次的挖矿节点:

  1. 大量运算能力强大、高网络带宽、大存储的v-node,执行POW,并提供SCS接入服务,维持整个网络必须的挖矿能力,这个数量在几千到一万。
  2. 海量cpu –based的SCS用于处理合约的执行。针对子链的共识多样性,这样的SCS节点甚至可以是手机等移动设备。SCS节点的数量可以不受限制。在目前的架构下,可以有几十万甚至几百万的SCS参与,而不会影响系统的性能。

2.3 子链

区块链有很多概念,比如分叉链,侧链,子链,它们分别都是什么东西呢?

分叉链指的是基于同一个软件的,增减一些功能后单独部署的一个区块链。

侧链指的是与主链相平行的单独一个区块链,但是它和主链之间可以通过相互了解的协议互联。主链的货币可以通过在主链的可验证的锁定,在侧链获得对应的货币,反之亦可。作为主链的补充,侧链可以提供一些主链不能提供的功能。但是这个互联对共识机制有要求,而且侧链必须有与主链相当的算力才能保证侧链货币的安全性。要达到相当的算力,其实完全就成了另外一个单独的链。所以侧链概念出来后一直没有太多的应用。

子链指的是在主链的平台上派生出来的具有其他功能的区块链。这些子链不能单独存在,必须通过主链提供的基础设施才能运行,并且免费获得主链的全部用户。一个简单的例子是以太坊上面的erc20 合约。这个合约可以看成是一个逻辑子链,但是这个子链的共识方式与主链一致。

由于墨客支持大量的子链而不会影响系统的总体性能,并且子链之间拥有良好的交互功能,因而墨客可以架构一个功能强大的立体结构。我们可以设想这么一些墨客的架构场景:

  1. 墨客的底层POW挖矿系统提供一个可靠的全局一致的区块链
  2. 快速处理智能合约并且能够随时更新SCS节点的PBFT子链
  3. 支持快速处理的零知识证明子链
  4. 由海量SCS节点(硬件盒子)构成的IPFS分布式文件系统子链
  5. 多个面向专业应用的行业子链
  6. 分布式子链token交易所
  7. 多个连接外部区块链系统的跨链子链

通过各个子链之间灵活的交互功能,一个子链可以使用另外一个子链提供的资源(比如IPFS),使得接入墨客系统的用户可以获得强大的分布式技术支持,从而使得在此基础上的构建应用变得非常简单,并且能够获得墨客系统的社区资源。

2.4 跨链

当前两个区块链的货币之间的兑换有两种方式,一种是采用线下的方式,找到一个可信的有相反需求的其他买家,甲把A货币转给乙,乙把对应的B货币转给甲。这样的办法比较低效,找到一个可信的对家很难,执行的风险也很大。另外一种方式就是普遍采用的中心化的交易所,大家把各自的货币充值到交易所,交易所在它的系统里面记录每个人的余额,然后兑换就在交易所的平台上面进行,直到买家从交易所取出相应的货币。

中心化的交易平台的问题显而易见。在监管缺失的情况下,中心化交易所可能存在内幕交易,伪造交易,资金挪用等等问题。而且中心化的交易所很容易受到主权机构的控制。

cross\_chain

cross_chain

这里通过公布X,同时解锁两个交易,实现跨链交易最重要的原子性问题。

但是这个解决方案有几个问题:

  1. 需要跨链的每个链都支持闪电网络,也就是需要哈希锁和时间锁的功能。现有的链如果没有这个功能的话,需要进行硬分叉。很多情况下并不现实。
  2. 整个交易的过程是个交互手动的过程。用户乙必须等待甲的公布,之后要确保在对方网络中递交合适的信息。如果需要实现自动化的话,会比较麻烦,需要额外的基础设施支持,比如类似Cosmos的拜占庭容错hub支持。

墨客采用系统特有的系统定时触发功能和子链的功能,完美解决了上述两个问题。

系统定时触发功能是设置在指定的未来区块位置执行某个交易。这个设置是100%会被执行。

cross\_chain

cross_chain

墨客具体的跨链这样实现:

  1. 找到匹配交易: 在墨客网甲从Am地址发送m个 MOAC:Am -> Bm : m, 另外一区块链网(例如以太坊)中乙从地址Be发n个Eth 到地址Ae,表示为( Am ->Bm : m ^ Be -> Ae : n )。
  2. 在墨客网络,甲创建一个哈希锁的系统定时触发交易T:Am ->Bm : m on Block#k。甲同时会把m MOAC发送到系统合约作为预备金。计算Hash(T)。
  3. 这个系统定时触发交易将在k block后执行这个交易。如果成功,Bm获得m MOAC,否则退回给Am。成功与否依赖于哈希锁是否被解锁:是否有可验证的以太坊交易Be->Ae : n eth,以及Hash(T) 标识。
  4. 乙看到系统定时触发交易T后,知道在k block后100%会执行,所以他可以很放心的发送交易Be->Ae : n eth, 同时将Hash(T)放入数据段。
  5. 乙在以太坊的交易确认后,监控子链将以太坊的交易信息作为参数调用系统合约,解开hash锁。
  6. 到k block之后,系统合约自动执行,完成Am->Bm : m。

这里,墨客区块链通过其他区块链的确认交易信息解锁墨客交易,实现原子操作。

其巨大优越性在于,对其他区块链没有新的要求,只需要交易能附加数据信息,这个功能每个区块链都有。因此,墨客跨链机制可以实现与所有的区块链的跨链操作!

目前墨客系统通过子链来实现拜占庭容错的快速消息传递。

举例:跟以太坊的信息传递

支持同一种自定义共识协议的SCS node之间可以形成一个子链。为了实现墨客系统与以太坊区块链之间的信息传递,SCS node可以同时连接一个eth的light node。

cross\_chain

cross_chain

这样,SCS node可以随时获得eth中的需要监控的交易信息。多个SCS node之间通过预定义的共识协议,将对应的操作(比如解锁系统合约的调用请求)发送到v-node层,从而实现跨链信息的拜占庭容错。

综上所述,墨客提供一个与其他所有区块链的跨链方案,同时提供跨链的信息传递,以实现去中心化的跨链交易。但是,不仅限于此,在此构架上可以很方便的实现去中心化的交易所。

2.5 挖矿

MOAC将系统分为两层,底层是POW挖矿,与现有的以太坊系统兼容,现有的以太坊矿机可以很方便的转移到墨客挖矿。上层是SCS node。这样的node数量可以非常巨大,每个部署的子链合约,可以随机挑选出参与挖矿的SCS节点,形成一个共识子网。SCS节点提供服务,并获得报酬。

cross\_chain

cross_chain

墨客提出了两级挖矿,上层挖矿提供了一个二次分配的功能。就是子链的部署者需要持续的付出MOAC,分配给参与的scs节点,以维持子链的正常运行。而SCS节点参与挖矿的成本很低,只需要一定的MOAC保证金,对系统的要求很低。这样的挖矿机制使得广大的SCS节点都可以参与并获得收益,从而使得MOAC的二次分配更加广泛。这样,可以极大的调动社区的积极性,形成一个开放的系统。

子链的缺省配置是用moac支付。子链的创建者可以设定每个block的时间间隔,以及每个block的reward。这些reward是由创建者支付。墨客提供一个动态的管理机制,使得即使MOAC本身的价值波动,仍然可以让scs节点有收益,同时子链创建者也不至于负担过重。

SCS English Version

子链是MOAC区块链中非常重要的一个模块。其主要目的在于分流母链中的业务逻辑,把一些比较繁琐的业务操作放在子链中执行。

子链由SCS节点组成,必须部署在母链Vnode上。

子链支持分片,每个分片都能独立完成业务逻辑。

子链中的节点随机组合,支持动态增减。

同时,在主链上,我们增加了代理的Vnode节点来保证子链的稳定性,这部分我们会在最后介绍。

当前,按功能分,有如下几种SCS节点类型: * 参与业务逻辑的SCS * 用于业务监控的SCS * 准备参与业务逻辑的SCS

下图为MOAC系统的示意图,子链在subchain1方框内 |moac\_subchian|

主要名词解释:

DAPP用户: 使用子链DAPP的用户

DAPP项目方: 子链DAPP的开发者。在本文档中,DAPP用户和项目方统称DAPP用户(开发者)

主网挖矿节点: 当前母链上运行的挖矿节点(MOAC-VNODE)

主网代理节点: 母链代理节点,用于提高子链节点的稳定性(VNODE-PROXY)

子链挖矿节点: 子链矿工节点,参与子链业务逻辑(SCS)

子链监控节点: 只用于查询子链业务状态,不参与共识(MONITOR)

智能合约: 当前有这样几种智能合约,本文档只解释与子链相关的智能合约

系统智能合约
    * 主链系统合约
    * 子链矿池智能合约subchainprotocolbase,用于子链SCS节点矿工加入矿工池
    * 代理智能合约vnodeprotocolbase:用于母链vnode提供代理功能,加入代理池
    * 子链控制合约subchainbase:用于子链控制逻辑,子链生成前和生成后的一系列控制逻辑
子链DAPP智能合约:用于部署子链业务逻辑的合约

DAPP用户部署子链时,只需要关注子链控制合约和子链DAPP智能合约。

子链运行流程

moac\_log

moac_log

墨客区块链——众链之母,革命性的商用区块链架构系统

MoacChain——The Mother of All Chains,A commercial blockchain architectural system of revolution

1. 关于墨客

1.1 墨客简介

Mother of All Chain (MOAC) Blockchain (简称 “MoacblockChain”,中文音译为“墨客区块链”)是一个开源的区块链平台,通过分层配置结构实现在P2P网络上支持多种子区块链,由硅谷顶级区块链专家团队研发,突破了异步合约调用、合约分片处理和跨链操作等当前业界难题,平台的扩展能力和对合约的处理速度远远优于当前如以太坊智能合约平台,是一款真正可以部署商业应用的区块链底层平台。

Moac旨在提供一种可扩展且有弹性的区块链,支持基于分层结构的状态交易,数据访问,和控制流程。它创建了一个框架以允许用户用高效的方式执行智能合约。它还提供了开发的体系结构,采用底层基础设施来快速简便地产生子区块链。它是一个区块链平台,可以为子区块链的架设提供必要的部件,为想法测试,私链部署,复杂任务处理和智能合同应用等提供解决方案。

1.2 发展历程

moac\_history

moac_history

1.3 创始团队

moac\_key\_person

moac_key_person

1.4 项目优势

硅谷一流团队: 墨客团队由井底望天、陈小虎、杨韵乐等数十位在硅谷有20年IT、6年区块链研发经验的顶级技术专家构成。此前,他们已经成功开发井通平台,并积累了4年区块链商业落地经验。

高速性能: 相对于以太坊每秒7-14次交易速度,墨客可以提高100倍,在优化条件下,甚至到1000倍的处理速度。

POP技术: 墨客采用独有的POP技术。其他系统要么坚持pow,要么坚持pos,要么混合pow+pos,都无法有效利用两者的优点,和避免两者的缺点。墨客采取底层物理网用pow,上层智能合约的逻辑网用 pos,使得两者的优点都能兼顾,可以称为pop (pos over pow)。

原子跨链: 墨客采用系统特有的系统定时触发功能和子链的功能,完美避免了需要修改被跨链的区块链底层及无法自动化的问题,使得墨客成为有跨链能力的区块链系统。

子链刷新过程

【参数】

子链刷新的参数在subchainbase.sol中定义。参数列表如下:

  • 1.刷新周期Round数值:定义子链经过多少区块后刷新。假如子链有100个节点,每个节点依次产生block,定义Round数为5,则每过500block 刷新一次。
  • 2.当前刷新id 索引:指定下次刷新的id 在Nodelist中 的索引值
  • 3.刷新过期数值expiration:指定的id在block [0, 2*expiration]必须完成刷新,否则由下一个id重新发起刷新。
  • 4.刷新作假惩罚:如果节点在propose,dispute,或者vote阶段作假,将从预先缴纳的bond中扣除相应的惩罚数额(MOAC),并被踢出NodeList

【流程】 * 1.Proposal的格式如下: image0

  • 2.刷新周期到的时候,SCS节点调用子链合约的createProposal,发起一个刷新请求交易flushTX
  • 3.V-node接受到flushTX后,处理相应的逻辑,并将推送消息到相应的scs node,告知有新的proposal。
  • 4.如果SCS node发现没有问题,它们不需要反应。
  • 5.如果SCS node发现这个proposal 有问题,它可以发起一个新的proposal,并通过TX调用DisbuteProposal,之后触发v-node将推送消息到相应的scs node。一旦SCS节点收到消息,那么所有的SCS必须响应,一个SCS只能对其中的一个进行投票(由智能合约保证)。
  • 6.最初发起proposal和发起disbute的SCS节点设置timer,在指导的时间内,获得投票的结果。如果得票超过50%,那么这个节点就发起一个TX来调用子链合约的Approval function。
  • 7.合法的proposal被接受,并被记录到区块链中,错误的proposal和所有对错误的proposal进行投票的人将被扣掉相应的保证金。

子链刷新过程与SubchainBase合约的调用 image1

报酬及罚金流向

子链SCS节点的选择

子链的SCS的节点选择通过三个步骤实现: * 1.子链设定一个需要选择的SCS节点数范围[min,max]。然后调用子链协议合约的getSelectionTarget(),根据当前的注册的SCS总数,得到一个selection target。 * 2.V-node比较子链地址和与自己相连的SCS地址的距离,如果小于selection target,则通知SCS。 * 3.SCS得到register的通知,必须主动调用子链的RegisterAsSCS来确定自己参与到该子链。

通过这样的选择方法,可以实现: * 1.选择的过程是随机的 * 2.SCS的选择根据当前的SCS节点总数自动调整 * 3.SCS的显示确认保证SCS的liveness

注:两个地址的距离(hash_dist)由RangeIndex[]定义的位数(index_range)来确定。 image0

子链介绍

子链是MOAC区块链中非常重要的一个模块。其主要目的在于分流母链中的业务逻辑,把一些比较繁琐的业务操作放在子链中执行。

子链由SCS节点组成,必须部署在母链Vnode上。

子链支持分片,每个分片都能独立完成业务逻辑。

子链中的节点随机组合,支持动态增减。

同时,在主链上,我们增加了代理的Vnode节点来保证子链的稳定性,这部分我们会在最后介绍。

当前,按功能分,有如下几种SCS节点类型: * 参与业务逻辑的SCS * 用于业务监控的SCS * 准备参与业务逻辑的SCS

子链的基本设计原理请参见前一章。

下图为MOAC系统的示意图,子链在subchain1方框内 |moac\_subchain1|

本章中的名词解释:

DAPP用户: 使用子链DAPP的用户

DAPP项目方: 子链DAPP的开发者。在本文档中,DAPP用户和项目方统称DAPP用户(开发者)

主网挖矿节点: 当前母链上运行的挖矿节点(MOAC-VNODE)

主网代理节点: 母链代理节点,用于提高子链节点的稳定性(VNODE-PROXY)

子链挖矿节点: 子链矿工节点,参与子链业务逻辑(SCS)

子链监控节点: 只用于查询子链业务状态,不参与共识(MONITOR)

智能合约: 当前有这样几种智能合约,本文档只解释与子链相关的智能合约 * 系统智能合约 * 主链系统合约 * 子链矿池智能合约subchainprotocolbase,用于子链SCS节点矿工加入矿工池 * 代理智能合约vnodeprotocolbase:用于母链vnode提供代理功能,加入代理池 * 子链控制合约subchainbase:用于子链控制逻辑,子链生成前和生成后的一系列控制逻辑 * 子链DAPP智能合约:用于部署子链业务逻辑的合约

DAPP用户部署子链时,只需要关注子链控制合约和子链DAPP智能合约。

子链刷新介绍(Flush)

在MOAC的设计中,子链用于完成DAPP用户的业务逻辑。此外,我们约定子链的状态需要在一定区块后,刷新状态到母链,并且结算相应的收益,这就是子链的刷新。

对于DAPP用户来说,需要在部署系统子链合约时约定刷新周期。刷新周期的相关设置可参见7.4->B1第六点。

刷新的收益详见7.9。

子链参与者的付出、奖励与惩罚

在MOAC的生态设计中,我们赋予参与MOAC的人各种角色。

作为SCS矿工,需要在注册时付出一定数量的押金(一般来说要大于10MOAC),来进入矿工池等待参与子链运行;此外,scsid需要存入1个moac作为调用费用。一旦被选中参与子链运行,矿工将会在子链刷新的时候获得回报,参与的子链越多,获得的回报越多。但是,如果SCS节点的网络不稳定,或者尝试捣乱,该SCS将会被标记为坏节点,继而被踢出子链的运行,并扣除押金。

作为DAPP用户,在部署控制合约的时候,需要消耗gas,之后需要给合约账号打入一定数量的运行费用,这些费用将会在刷新的时候分发给矿工。

作为代理Vnode节点,需要在注册的时候交押金,可以获得两种类型的奖励,一种是提供代理节点数据转发后的收益,此收益可通过调用代理合约withdraw实现,另一种是提供子链合约调用的节点收益,此收益会在刷新后收到。

DAPP Developers

DAPP Developer can create a MicroChain and running his DAPP on the MicroChain. He need to deposit enough MOAC in the MicroChain to reward the SCSs running the MicroChain.

DAPP Developer need to make his own MicroChain contract or use some template provided by MOAC.

B1、Deploy MicroChain control contract

subchainbase is the contract for the DAPP developers to control the MicroChain. It provides the MicroChain launch and running methods.

The parameters are as following:

  1. proto:subchainprotocolbase contract address, obtain from MOAC team;
  2. vnodeProtocolBaseAddr:vnodeprotocolbase contract address,obtain from MOAC team;
  3. min:min SCSs required to launch MicroChain, suggest value > 3;
  4. max:max SCS required to launch MicroChaib, suggest value < 100;
  5. thousandth:default is 1;
  6. flushRound:MicroChain flush interval between MotherChain blocks, min number is 100;
  7. The gas limit need set to 6700000 for deploying.

Example:

chain3.personal.unlockAccount(mc.accounts[0], 'passwd',);//unlock the account to deploy
var proto = "0x8fab1913cc......2deb725" ;
var vnodeProtocolBaseAddr = "0x8fab1913c......2db52deb725" ;
var min = 1 ;
var max = 10 ;
var thousandth = 1 ;
var flushRound = 20 ;
var subchainbaseContract = chain3.mc.contract([{"constant":true,"inputs":[],"name":"maxMember",......,"type":"event"}]);
var subchainbase = subchainbaseContract.new(
   proto,
   vnodeProtocolBaseAddr,
   min,
   max,
   thousandth,
   flushRound,
   {
     from: chain3.mc.accounts[0],
     data: '0x6060604052600c601555670d...708e8ee3c23da8b02d0278eb0029',
     gas: '6700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

B2、RegisterOpen:

The RegisterOpen is doing the following tasks:

  • Dapp developer call this function on MotherChain to start the MicroChain;
  • MotherChain broadcast the call to all the VNODES. If the VNODE contains a valid SCS, it will wait for the selection signal;
  • If SCS receives a selection signal, it need to send a transaction to the MicroChain contract to finish the registeration (This is why SCS need to have some initial MOAC deposit).
  • MicroChain will collect the confirmations undtil it reaches the max limit as defined in the contract.

The MicroChain chooses in the SCS pool to form the microChain validators. By default, this process is random. The microChain creator can also change the selection process and only allow specific SCSs to join.

Example:

function subchainRegisterOpen(dappAddr,dappPasswd,subchainAddr)
{
    chain3.personal.unlockAccount(dappAddr, dappPasswd,0);
    sendtx(dappAddr, subchainAddr, '0','0x5defc56c' );
}

Comments:

  • dappAddr、dappPasswd:Dapp Developer account and password to make the call;
  • subchainAddr: subchainbase contract address;
  • data:In sendtx, ‘0x5defc56c’ is a constant to send with. It was generate from the first 4 bytes in the hash of registerOpen() function.

Example:

subchainRegisterOpen('0x1b9ce7e4f15...38913a56cd986786',
‘123’,
'0x6f5b81365fb1d3d...536cc78749af2c')

After registerOpen is called,DAPP developer can use the following methods to check how many SCS nodes registed in the MicroChain:

Method 1:

In the Console, check after call RegisterOpern in subchainBase:

This is to call the nodeCount function in subchainBase contract.

> subchainBase.nodeCount()

Method 2:

In the Console, call the subchain address to check the value of nodeCount (‘0x0e’):

> mc.getStorageAt(subchainAddr,0x0e)

When enough SCS nodes registerd in the MicroChain, continue to next Step: RegisterClose().

B3、RegisterClose:

The RegisterClose is doing the following tasks:

  • Dapp developer call the RegisterClose function;
  • The contract checks if the number of SCS registered is larger than the min number required in the MicroChain contract. If yes, continue. Otherwise, the register is void;
  • The contract is broacast to all the VNODEs and SCSs that the registration is closed;
  • The registered SCSs receive this broachasting, init the MicroChain and start generating MicroChain blocks.

After RegisterClose,SCSs cannot register through the MicroChain contract. The SCSs registered can participate the and get rewards from the MicroChain.

Example:

function subchainRegisterClose(dappAddr,dappPasswd,subchainAddr)
{
    chain3.personal.unlockAccount(dappAddr, dappPasswd,0);
    sendtx(dappAddr, subchainAddr, '0','0x69f3576f' );
}

Comments:

  • dappAddr、dappPasswd:Dapp developer account and password to send the TX;
  • subchainAddr:MicroChain contract subchainbase address;
  • ‘0x69f3576f’: constant, generated from the subchainbase registerClose() function by using Keccak256 hash.

Example:

subchainRegisterClose('0x1b9ce7e4f15......e0e38913a56cd986786',
‘123’,
'0x6f5b81365fb1d3......6907fa536cc78749af2c')

Besure to have enough SCS nodes registered befor calling Registerclose. Otherwise you need to start the process again.

B4、Deploy DAPP contract on the MicroChain

DAPP contact can be deployed on the MicroChain through directcall. Directcall can be performed under the console using mc.sendTransaction.

  1. from: The DAPP source account, need to unlock;
  2. value: Direct call don’t need any mc, you can put any non negative number here, suggest 0.
  3. to: MicroChain contract subchainbase address;
  4. gas: Direct calls don’t use any gas, put 0;
  5. gasPrice: Direct calls don’t use any gas, put 0;
  6. shardingflag: Need to set value to ‘0x1’;
  7. nonce: Note this is the nonce for the MicroChain.
  8. data: The data is generated from compiled DAPP contract. After compiled the DAPP contract, you need to put the BIN as data.
  9. via: this need to be a VNODE-PROXY address. You can get this address by run a local MOAC VNODE as proxy or use one from others.

To check the deploy results, referring to B6.

Example:

function deploycode()
{
    chain3.personal.unlockAccount(mc.accounts[0],'',0);
    chain3.mc.sendTransaction(
        {
            from: mc.accounts[0],
            value:chain3.toSha('0','mc'),
            to: subchainbase,
            gas: "0",
            gasPrice: "0",
            shardingflag: "0x1",
            nonce: 1,
            data: '0x606060405234156......9c6697187ac00029',
            via: '0x78e1b4584085......e3cff29f11f8d5e08f54dc'
        });

    console.log('sending from:' +     src + ' to:' + tgtaddr  + ' with data:' + strData);
}

B5、DAPP function calls

To make the DAPP function calls, users also need to make a direct call. First, user need to compile the DAPP function calls and saved in the data section. Then send a transaction to MicroChain address, with correct parameters (B4). The results can be checked later (B6).

Example:

function testSet(num)
{
    chain3.personal.unlockAccount(mc.accounts[0],'',0);
    chain3.mc.sendTransaction(
        {
            from: mc.accounts[0],
            value:chain3.toSha('0','mc'),
            to: subchainbase,
            gas: "0",
            gasPrice: "0",
            shardingflag: "0x1",
            nonce: num,
            data: '0x4f2be91f',
            via: '0x78e1b45840850......ff29f11f8d5e08f54dc'
        });

    //console.log('sending from:' +     src + ' to:' + tgtaddr  + ' with data:' + strData);
}

B6、Check MicroChain status

The status of the DAPP can be checked through SCS monitor service. User can start a SCS with monitor service by using the RPC option:

  • -rpcaddr [addr] SCS turn on rpc ip
  • -rpcport [port] SCS turn on rpc port

Data structure:

type Args struct {
    Sender       common.Address      // Dapp owner
    SubChainAddr common.Address
}
type ArgsData struct {
    Sender       common.Address     // Dapp owner
    SubChainAddr common.Address
    Func         string             // eg:"SetData()", "rpcGetData()"
}

SCS RPC reference

GetScsId

func GetScsId(args *Args, reply *common.Address) error

Return the SCSID of SCS.

Parameters: args - MicroChain id reply - Returned SCS id

Example:

client, err := rpc.DialHTTP("tcp", serverAddress+":"+serverPort)
var scsid common.Address
client.Call("ScsRPCMethod.GetScsId", Args{}, &scsid)

GetNonce

func GetNonce(args *Args, reply *uint64) error

Return the MicroChain nonce.

Parameters: args - MicroChain id reply - returned nonce value

Example:

args := Args{sender, subChainAddr}
var noce uint64//
client.Call("ScsRPCMethod.GetNonce", args, & noce)

GetData

func GetData(argsData *ArgsData, reply *[]byte)

Return a function value in DAPP contract. The funcation need to have not input parameters.

Example:

var replyData []byte
argsData := ArgsData{sender, subChainAddr, "GetData()"}
client.Call("ScsRPCMethod.GetData", argsData, &replyData)

GetDappState

func (scs *ScsRPCMethod) GetDappState(args *Args, reply *uint64) error

Return the DAPP contract status

  • 0: not created;
  • 1: created successfully;

Example:

args := Args{sender, subChainAddr}
var reply uint64
client.Call("ScsRPCMethod.GetDappState", args, &reply)

GetContractInfo:

Check DAPP MicroChain using http protocol.

Parameters:

type ContractInfoReq struct {
    Reqtype      int//Request type: 0 - all; 1 - Array; 2 - mapping; 3 - structure; 4 - short types; 5 - long types, such as string, bytes;
    Key          string//64 bytes HEX string, this is the index of the variable in the contract. Optional if request all variables.
    Position     string//64 bytes HEX string,when Reqtype=1,this is the variable index in the array; when Reqtype = 2, this is the mapping indes.
    Structformat []byte//Only used for structure type, 1 - single; 2 - list; 3 - string;
}

type GetContractInfoReq struct {
    SubChainAddr common.Address//contract address of DAPP
    Request      []ContractInfoReq//Variables requested.
}

Returned parameters:

type ContractInfo struct {
    Balance  *big.Int
    Nonce    uint64
    Root     common.Hash
    CodeHash []byte
    Code     []byte
    Storage  map[string]string
}

Please follow these steps to start your MicroChain mining:

A1、Download SCS program ( Or power up a SCS hardware miner)

The initial SCS program has following files: README - A txt file contains instructions; config/userconfig.json - Configura file used with SCS, need to be customized before start SCS; scsserver/scsserver - Executable program of SCS

A2、Cusomize userconfig.json

The conten of the userconfig.json is as following:

  1. VnodeServiceCfg:The VNODE IP and port SCS connects to. Each SCS needs to connect a VNODE to communicate with the MotherChain. You can setup a local VNODE or use a truste VNODE from other sources;
  2. DataDir:SCS data directory that holding the MicroChain data. Default is “./scsdata”;
  3. LogPath:SCS log directory, default is “./logs”;
  4. Beneficiary:Account holds the MicroChain mining rewards. Please don’t use the SCS account for this. We suggest you create this account separatly and don’t put the keystore file on SCS.
  5. VnodeChainId:network id with the MotherChain. Testnet = 101 and mainnet = 99. If you have a custome network, you need to make sure the vnode connect with has the same network id.
  6. Capability: desposit limit for a MicroChain. Since each MicroChain requires some desposit to join, you can set this number and only join the MicroChain with deposit requirement less than this limit.
  7. ReconnectInterval: If the connection is lost with vnode, SCS will try to connect with the vnode again. This is the number of seconds between each connection with vnode.

A3、Start SCS

Command options (SCS -h)

-p [psd]           Start SCS with a password for the scsid keystore,default password is "moacscsofflineaccountpwd"
-rpcaddr [addr]    SCS start with rpc ip
-rpcport [port]    SCS start with rpc port

After the first start,SCS generates a keystore with a password (default or provided by user). The address of this keystore is the scsid. This address won’t receive rewards. If user want to use a different scsid, should remove the keysore file and restart the SCS.

SCS also has a rpc port. Currently the RPC only has monitoring services for DAPP developers.

A4、Register the SCS into a SCS pool

To participate in the MicroChain, SCS need to register itself into a SCS pool. When it registers, the SCS need to pay deposit as required by the SCS pool (defined in subchainprotocolbase.sol). After it is registered, it need to wait for some blocks (default is 50 blocks) to be chosen by MicroChains.

One SCS can register multiple MicroChains.

Javascript method to register the SCS: (used under VNODE console)

function protocolRegister(baseAddr,basePasswd,protocolAddr,scsAddr)
{
    chain3.personal.unlockAccount(baseAddr, basePasswd,0);
    sendtx(baseAddr, protocolAddr, '10','0x4420e486000000000000000000000000' + scsAddr);
}

Explainations

  • baseAddr、basePasswd:MOAC VNODE account used to send TX;
  • protocolAddr:The subchainprotocolbase contract address;
  • scsAddr:scsid address, saved in “…/scsserver/scskeystore”;
  • deposit: amount of MOAC to send to pools to join MicroChains;
  • data:‘0x4420e486’ is a constant used to call the MicroChain. It was from the subchainprotocolbase function ‘register(address scs)’ . Don’t change it unless you know what you are doing here!

Examples:

register SCS

protocolRegister ('0x1b9ce7e4f1.......e38913a56cd986786',
‘123’,
'0x09f0dfc09b......0b85e5189a7493671',
'f687272ae00f8cea......37dd9be30329d8cf')//without prefix '0x'

Send a transaction

function sendtx(src, tgtaddr, amount, strData) {
    chain3.mc.sendTransaction(
        {
            from: src,
            value:chain3.toSha(amount,'mc'),
            to: tgtaddr,
            gas: "9000000",
            gasPrice: chain3.mc.gasPrice,
            data: strData
        });

    console.log('sending from:' +   src + ' to:' + tgtaddr  + ' with data:' + strData);
}

OK, now SCS miner finished setup and you can sit back and wait for your rewards. All the rewards can be seen after a MicroChain flushed its data into the MotherChain and you can see the balances changes in the Beneficiary account address.

FAQ:

  1. What’s the deposit for?

The process for a SCS node to join a microChain is: make a safety deposit and register in the SCS pool. The amount of the deposit is a parameter that can be set in the microChain protocol. SCS cannot choose the microChain by itself.

The microChain will choose in the SCS pool to form the microChain validators. By default, this process is random. The microChain creator can also change the selection process and only allow specific SCSs to join. When microChain generate a new block, if a SCS made bad decision, it will be punished with penalty of the deposit. The microChain will drop a SCS if it made many bad decisions.

  1. How secure are microchains against 51% attack? Or are there different security measures applied on microchain level?

    Generally there are two ways to prevent inside attackers in a public microChain. First, all the SCS join the SCS pool need to pay some deposits and will be kicked out of the microChain if it made enough bad decisions. This can cost the attacker more than they can earn in a public microChain. Second, the microChain was formed by randomly choosing SCSs from the SCS pool. Thus, it is very hard for the attacker to get enough SCSs to do the 51% attack (33% for PBFT). For a SCSs pool with 100 nodes, the attackers may need 51 nodes to perform the 51% attack for a microchip with only 20 nodes.

MicroChain User

There are three major players in MicroChain:

  • A、 SCS miner:run SCS and join the MicroChain consensus to get MicroChain rewards;
  • B、 DAPP developer:develop DAPP and deploy its Smart Contract on the MicroChain;
  • C、 VNODE proxy:provide a VNODE-PROXY to MicroChain.

In the MOAC ecosystem, these players have different responsibility and rewards:

  • A. SCS miner: A SCS miner needs to deposit some MOAC to join a MicroChain mining pool. When a SCS was chosen by one MicroChain and start mining, it can receive MicroChain mining rewards as long as the MicroChain is running. The rewards usually was given as MOAC and shows up after a flush of the MicroChain. The deposit will be deducted if the SCS keeps sending dishonest transactions or lost connections very often.
  • B. DAPP developer: When the DAPP developer deploy his Contract on the MicroChain, he need to deposit enough MOAC to pay the SCS miners for their work. These MOAC will be distributed to the SCSs after each MicroChain block generated, and saved to the MotherChain after MicroChain flush.
  • C. VNODE proxy: Need to pay deposit to register as proxy. It can get rewards from participting in the MicroChain and from transfer data of MicroChains.

For the details of the deposit amount and how to get rewards, please refer to the smart contracts defined them:

  1. subchainprotocolbase
  2. subchainbase
  3. vnodeprotocolbase

We suggested the users use official pools for our testing, so we can find bugs and problems in the testnet. In the future, users can form their own pools and benefit from them.

VNODE-PROXY

In MOAC system,VNODE-PROXY(VP) is used to provide MicroChain register and data services. VP is a VNODE that can get rewards from MicroChains without mining. You just need to set the VnodeBeneficialAddress in the vnodeconfig.json.

To provide MicroChain register service, VP need to publish its VnodeBeneficialAddress to the MicroChain users.

To provide data service to MicroChains, VP need to register in the Proxy contract to be selected:

The function call to register vnode is:

function vnodeRegister (baseAddr,basePasswd, vnodeAddr,vnodeChain)
{
    chain3.personal.unlockAccount(baseaddr,basename);
    sendtx(baseaddr, vnodeChain, '1','0x32434a2e000000000000000000000000' + vnodeAddr //data1
    +'0000000000000000000000000000000000000000000000000000000000000040'//data2
    +'0000000000000000000000000000000000000000000000000000000000000013'//data3
    //1 9 2 . 1 6 8 . 1 0 . 1 6 : 5 0 0 6 2
    +'3139322e3136382e31302e31363a353030363200000000000000000000000000');//data4
}

Commenets:

  • baseAddr、basePasswd:Dapp Developer need to use the password to unlock the account;
  • vnodeChain:VNODE-PROXY contract address;
  • vnodeAddr:VnodeBeneficialAddress in vnodeconfig.json;
  • data1:‘0x32434a2e000000000000000000000000’ is the call to contract VNODE-PROXY function ‘register(address vnode, string link)’, ‘1’ means 1 moac as deposit;
  • data2:string data type;
  • data3:string data length;
  • data4:string content;

Commands to call register vnode:

vnodeRegister ('0x1b9ce7e......1e0e38913a56cd986786',
‘123’,
'0x1b9ce7e4f156c1a28f......38913a56cd986786',
'0x979b01d62ae09dfce5......95541bd32580de66')

A1、下载SCS代码(或准备一个SCS盒子)

A2、配置SCS配置文件userconfig.json,需要配置的内容如下

  1. VnodeServiceCfg:这个SCS需要连接的vnode的ip和port。如架构图,每个SCS需要连接一个MOAC-VNODE来进行通讯,所以如果你没有自己部署一个节点,需要从官方渠道来设置连接一个可用的MOAC-VNODE
  2. DataDir:SCS数据目录,以子链地址为文件夹存放子链数据。默认:./scsdata
  3. LogPath:SCS日志目录,以天为单位存放日志。默认:./logs
  4. Beneficiary:矿工收益账号。为了安全起见,我们建议采用与scsid不同的账号用来获取子链的收益(scsid将会在后面讲到)
  5. VnodeChainId:母链ID,当前,测试环境ID是101,正式环境ID是99,请按需设置,不要设置其他ID
  6. BondLimit:服务子链的押金上限。每个DAPP用户需要设置押金来为子链服务,矿工可以使用这个上限来选择不为押金高的子链服务。该押金将从register时候的保证金中扣除。(TODO)

A3、启动SCS

参数说明

  • “-p [密码]” scsid的密码,不设置默认密码为 moacscsofflineaccountpwd
  • “-rpcaddr [addr]” SCS开启rpc的ip
  • “-rpcport [port]” SCS开启rpc的port

启动后,SCS将会在当前目录下生成一个keystore目录,并在目录中新建一个账号,这个账号就是scsid,可在第一次启动时使用-p设置密码。如果想换一个scsid,则需要删除keystore中的内容重新启动。

SCS的rpc功能是提供给DAPP用户查询用的(MONITOR),如果是矿工,可以不开启这个功能。

A4、将这个SCS注册到SCS池子中去

SCS根据子链矿池智能合约subchainprotocolbase进行注册,并缴纳保证金。在等待一定时间之后(通常是母链50个block),就进入子链矿池,成为该子链的候选SCS节点。

只要性能允许,一个SCS可以参与多个子链的注册。

注册子链协议Javascript方法:(请注意,所有js方法需要和MOAC-VNODE Console配合使用,之后的例子相同)

function protocolRegister(baseAddr,basePasswd,protocolAddr,scsAddr)
{
    chain3.personal.unlockAccount(baseAddr, basePasswd,0);
    sendtx(baseAddr, protocolAddr, '10','0x4420e486000000000000000000000000' + scsAddr);
}

【说明】:

  • baseAddr、basePasswd:moac主网端存在的一个账户及其密码,用来发送交易前账户解锁;
  • protocolAddr:子链矿池合约subchainprotocolbase地址;
  • scsAddr:scsid地址,放在“…/scsserver/scskeystore”目录下;
  • 保证金:这里最低交10个moac,实际根据协议合约的最低保证金要求,保证金交的越多,可以参与的子链数量越多;
  • 数据:‘0x4420e486’是子链矿池合约subchainprotocolbase中‘register(address scs)’通过hash算法Keccak256得到前4个字节;该函数带一个参数,每个参数占用32个字节,地址20字节,不足32字节则前补12字节00。这里不用修改。

另附1调用实例:

protocolRegister ('0x1b9ce7e4f1.......e38913a56cd986786',
‘123’,
'0x09f0dfc09b......0b85e5189a7493671',
'f687272ae00f8cea......37dd9be30329d8cf')//不带0x开头

另附2交易实例:

function sendtx(src, tgtaddr, amount, strData) {
    chain3.mc.sendTransaction(
        {
            from: src,
            value:chain3.toSha(amount,'mc'),
            to: tgtaddr,
            gas: "9000000",
            gasPrice: chain3.mc.gasPrice,
            data: strData
        });

    console.log('sending from:' +   src + ' to:' + tgtaddr  + ' with data:' + strData);
}

注意:注册时缴纳的保证金,将在SCS被选中做子链的时候临时扣除,用于做假惩罚。

至此,矿工的前期工作全部完成,如果被选中参与子链的运行,将会在子链刷新之后,在Beneficiary中看到收益。

TXdebug

blockHash: “0xdfbc9882a35dbc7f069467496bb6380965e436bd3d1bfcea53a480c2e596bc6c”, blockNumber: 310031, contractAddress: “0xb76b578e22fe2f39bcd501808d083d7a788ab948”, cumulativeGasUsed: 137561, from: “0xbc2bb569cd460ae5c517c777f84b97e8f27bf084”, gasUsed: 137561,

blockHash: "0xc8e8d03a00aa0ba6b060558dd028bd4dd33d7a6d5380c639e2d63f80d84ac0fd",

blockNumber: 308954, contractAddress: “0x3dee8f2acc17859c11558168a8114bec124c04f9”, cumulativeGasUsed: 137587, from: “0xbc2bb569cd460ae5c517c777f84b97e8f27bf084”, gasUsed: 137587,

mc.getTransactionReceipt(t3) { blockHash: “0xaeafe2ccd3e8ee27daad32e97a0cb94396688c59a9730aa504339f3f9edf7185”, blockNumber: 308924, contractAddress: “0xbc2bb569cd460ae5c517c777f84b97e8f27bf084”, cumulativeGasUsed: 1004, from: “0x3ba33d1bcd95fedad81ee9eed8aaf163af785bb6”, gasUsed: 1004, logs: [],

Backup模块

Backup其实是一个普通的SCS节点。但Backup不在子链生成时出现,而是在子链运行过程中按照一定规则加入到子链中来。Backup的目的是维持一个子链长久运行。 当前,Backup需要手动加入到队列中,方法如下:

function testregisterAdd(dappAddr,dappPasswd,subchainAddr)
{
        chain3.personal.unlockAccount(dappAddr,dappPasswd,0);
        sendtx(dappAddr, subchainAddr, '0','0xbe93f1b30000000000000000000000000000000000000000000000000000000000000020');
}

【说明】: * dappAddr、dappPasswd:Dapp用户用来发送交易前账户解锁; * subchainAddr:部署子链合约得到的合约地址; * 数据:‘0xbe93f1b3’是子链控制合约subchainbase中‘registerAdd()’通过hash算法Keccak256得到前4个字节;一次性最大添加32个scs作为backup

另附1【参考实例】:

subchainRegisterAdd('0x1b9ce7e4f156c......8913a56cd986786',
‘123’,
'0x6f5b81365fb1......907fa536cc78749af2c')

通过registerAdd,候选SCS加入Backup,作为Backup的SCS处于运行状态并同步其他SCS节点的区块数据,同步完成后通知子链完成加入;此时可参与子链的相关业务,如:处理交易、出块、刷新等。

在后续迭代版本中,Backup将会是一个自动的模块。

子链用户类别

在初步了解了SCS的构成后,对于想参与到MOAC子链的人来说,有三种参与方式: * A、 SCS矿工:参与子链的节点共识并获得子链挖矿奖励; * B、 DAPP开发者:作为子链DAPP开发者参与子链的业务逻辑开发; * C、 VNODE代理:提供一个VNODE-PROXY,参与子链的匿名信息传递。

在MOAC的生态设计中,参与子链的角色有不同的责任和收益。

A. SCS矿工,需要在注册时付出一定数量的押金(一般来说要大于10MOAC),来进入矿工池等待参与子链运行;此外,scsid需要存入1个moac作为调用费用。一旦被选中参与子链运行,矿工将会在子链刷新的时候获得回报,参与的子链越多,获得的回报越多。但是,如果SCS节点的网络不稳定,或者尝试捣乱,该SCS将会被标记为坏节点,继而被踢出子链的运行,并扣除押金。子链刷新(flush)是指子链的状态需要在一定区块后,刷新状态到母链,并且结算相应的收益。

B. DAPP开发者,在部署控制合约的时候,约定刷新周期,需要消耗gas,之后需要给合约账号打入一定数量的运行费用,这些费用将会在刷新的时候分发给矿工。

C. Vnode代理,需要在注册的时候交押金,可以获得两种类型的奖励,一种是提供代理节点数据转发后的收益,此收益可通过调用代理合约withdraw实现,另一种是提供子链合约调用的节点收益,此收益会在刷新后收到。

对于A和C,我们使用智能合约subchainprotocolbase和vnodeprotocolbase来部署建立两个池子,可供需要的参与者注册。详细方法将在下面叙述。

当前阶段,我们建议参与者使用官方推荐的池子,这样可以保证节点被最大化的利用。商用后,用户可根据需要定制自己的池子,吸引参与者注册。

SCS English Version

子链是MOAC区块链中非常重要的一个模块。其主要目的在于分流母链中的业务逻辑,把一些比较繁琐的业务操作放在子链中执行。

子链由SCS节点组成,必须部署在母链Vnode上。

子链支持分片,每个分片都能独立完成业务逻辑。

子链中的节点随机组合,支持动态增减。

同时,在主链上,我们增加了代理的Vnode节点来保证子链的稳定性,这部分我们会在最后介绍。

当前,按功能分,有如下几种SCS节点类型: * 参与业务逻辑的SCS * 用于业务监控的SCS * 准备参与业务逻辑的SCS

下图为MOAC系统的示意图,子链在subchain1方框内 |moac\_subchian|

主要名词解释:

DAPP用户: 使用子链DAPP的用户

DAPP项目方: 子链DAPP的开发者。在本文档中,DAPP用户和项目方统称DAPP用户(开发者)

主网挖矿节点: 当前母链上运行的挖矿节点(MOAC-VNODE)

主网代理节点: 母链代理节点,用于提高子链节点的稳定性(VNODE-PROXY)

子链挖矿节点: 子链矿工节点,参与子链业务逻辑(SCS)

子链监控节点: 只用于查询子链业务状态,不参与共识(MONITOR)

智能合约: 当前有这样几种智能合约,本文档只解释与子链相关的智能合约

系统智能合约
    * 主链系统合约
    * 子链矿池智能合约subchainprotocolbase,用于子链SCS节点矿工加入矿工池
    * 代理智能合约vnodeprotocolbase:用于母链vnode提供代理功能,加入代理池
    * 子链控制合约subchainbase:用于子链控制逻辑,子链生成前和生成后的一系列控制逻辑
子链DAPP智能合约:用于部署子链业务逻辑的合约

DAPP用户部署子链时,只需要关注子链控制合约和子链DAPP智能合约。

Monitor模块

Monitor是一个特殊的SCS节点,它是一种模式,DAPP用户可以通过这个节点来监控自己的子链运行状态和业务数据。

SCS启动时的RPC参数就是为这个模块设定的。

Monitor不参与子链共识,因此只能查看,不能修改数据。

即使子链已经运行,Monitor也能注册加入。

Monitor SCS启动后,DAPP用户通过调用子链控制合约subchainbase中的registerAsMonitor方法使Monitor SCS接入子链同步数据。

另附1registerAsMonitor调用方法:

function subchainRegisterAsMonitor (dappAddr,dappPasswd,subchainAddr,scsAddr)
{
    chain3.personal.unlockAccount(dappAddr, dappPasswd,0);
    sendtx(dappAddr, subchainAddr, '0', '0x4e592e2f000000000000000000000000' + scsAddr );
}

【说明】: * dappAddr、dappPasswd:Dapp用户用来发送交易前账户解锁; * subchainAddr:部署子链合约得到的合约地址; * scsAddr:scsid地址,放在“…/scsserver/scskeystore”目录下; * 数据:‘0x4e592e2f’是子链控制合约subchainbase中‘registerAsMonitor(address monitor)’通过hash算法Keccak256得到前4个字节;该函数带一个参数,每个参数占用32个字节,地址20字节,不足32字节则前补12字节00。这里不用修改。

另附2调用实例:

代理Vnode节点(VNODE-PROXY)

在MOAC系统中,代理Vnode节点被用于提供子链调用服务和子链历史数据中转服务的节点。启动代理节点的方法和启动母链矿工节点的方法类似。但是,需要额外在vnodeconfig.json的VnodeBeneficialAddress里设置收益账号。

当提供子链调用合约服务时,需要调用子链时的via字段,设置和VnodeBeneficialAddress相同,否则该节点将不会工作。

在提供子链历史数据服务前,需要先向代理合约注册此节点以便被随机选中进行中转,方法如下:

另附1添加代理Vnode节点的Javascript方法:

function vnodeRegister (baseAddr,basePasswd, vnodeAddr,vnodeChain)
{
    chain3.personal.unlockAccount(baseAddr,basePasswd);

    sendtx(baseaddr, vnodeChain, '1','0x32434a2e000000000000000000000000' + vnodeAddr //数据1
    +'0000000000000000000000000000000000000000000000000000000000000040'//数据2
    +'0000000000000000000000000000000000000000000000000000000000000013'//数据3
    //1 9 2 . 1 6 8 . 1 0 . 1 6 : 5 0 0 6 2
    +'3139322e3136382e31302e31363a353030363200000000000000000000000000');//数据4
}

【说明】: * baseAddr、basePasswd:Dapp用户用来发送交易前账户解锁; * vnodeChain:部署VNODE-PROXY合约得到的合约地址; * vnodeAddr:vnodeconfig.json的VnodeBeneficialAddress * 数据1:‘0x32434a2e ‘是VNODE-PROXY合约 中‘register(address vnode, string link)’通过hash算法Keccak256得到前4个字节,本例押金交1moac;本例带两个参数; * 数据2:string数据类型; * 数据3:string数据长度; * 数据4:string内容

另附2调用实例:

vnodeRegister ('0x1b9ce7e......1e0e38913a56cd986786',
‘123’,
'0x1b9ce7e4f156c1a28f......38913a56cd986786',
'0x979b01d62ae09dfce5......95541bd32580de66')

Indices and tables