账户模型

账户模型概述

    由于 Vision 在设计过程中采用的是账户模型,所以在 Vision 中, 账户是链上事务交易参与的主体。 账户代表了节点和用户的身份. Vision 的所有活动都是围绕着账户进行的。在Vision中地址(  Address ) 唯一地标识了账户。在很多的事务中我们都需要提供参与事务的账户地址, 以表征参与者的身份。每个账户中都保存了与账户相关的数据。 比如账户拥有的VS基础币, Token余额, 智能合约(Smart Contract), 光量子(Photon), 熵(Entropy)等各种资源。与账户地址成对出现的是账户的私钥(可能有不同的表现形式)。对账户进行操作的时候我们需要使用到私钥, 私钥对账户参与的事务进行签名, 以验证该事务的有效性。账户可以通过发起交易的方式转入或者转出账户中的资源(比如VS或者Token), 与此同时, 需要消耗账户的光量子。账户也可以发布并拥有智能合约, 还可以调用他人发布的智能合约, 与此同时, 需要消耗账户的熵.  配置在 Vision 运行节点中的账户可以申请成为第一验证者( First Validator )并且接受其他账户的投票(Ballot). 当然账户也可以为自己投票.   总而言之,Vision 的一切活动都是围绕着账户来展开的。

账户创建方法

(1) 首先我们需要在系统中生成私钥和地址. 生成私钥和地址的方式有很多种, 如果我们自己搭建了底层节点的话, 我们可以通过访问节点的http或者rpc端口获取. 如果我们没有搭建底层节点的话, 我们可以使用钱包客户端或者在浏览器中获取. 然后我们需要激活账号. 有以下两种方式来激活账号, 由已有老账户往目标地址发送VS或者VRC-10 Token, 然后广播到网络即可完成账户的激活. 或者是在合约中进行VS/VRC-10转账, 此时需要多消耗掉25,000熵.

(2) 通过调用CreateAccount内置合约, 完成创建账户

如果账户有足够的光量子, 那么创建账户只会消耗光量子(大约300PhotonPoint), 否则, 创建账户会烧掉0.1个VS.

合约中的VRC-20转账不会创建账号, 但可以通过Visionscan查询到未激活账号的代币余额.

生成密钥对算法

Vision的签名算法为ECDSA,选用曲线为SECP256K1。其私钥为一个随机数,公钥为椭圆曲线上一个点。生成过程为,首先生成一个随机数d作为私钥,再计算P = d * G作为公钥;其中G为椭圆曲线的基点。

地址格式说明

用公钥P作为输入,计算SHA3得到结果H, 这里公钥长度为64字节,SHA3选用Keccak256。
取H的最后20字节,在前面填充一个字节0x46得到地址。

对地址(address)进行basecheck计算得到最终地址,所有地址的第一个字符为V。

其中basecheck的计算过程为:首先对地址(address)计算sha256得到h1,再对h1计算sha256得到h2,取其前4字节作为check填充到地址(address)之后得到address||check,对其进行base58编码得到最终结果。

我们用的字符映射表为:
ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

📘

地址格式对等

因为与以太坊使用相同的密钥对算法,Vision为了方便记忆与存储在地址侧做了些变换。例如
Vision侧一个地址
V开头地址:VRbNprwjvBomKhvnhZq7Y33JRcrQJethpc
46开头:46A3CFA732C835233DB3D6BF5F4A3C2D45B02EB6B9

与其对等的以太坊格式地址为
0x开头: 0xA3CFA732C835233DB3D6BF5F4A3C2D45B02EB6B9

这三个地址都对应者一个账户。调用Vision原生接口时使用V开头或者46开头地址,通过visible参数选择格式。调用Vision的JRPC接口时候使用0x开头地址。

签名说明

步骤

1.取交易的rawdata,转成byte[]格式。
2.对rawdata进行sha256运算。
3.用交易每个合约中地址对应的私钥(现在一般就是一个合约,一个私钥),对sha256的结果进行签名。
4.把签名结果添加到交易中。

算法

1.ECDSA算法,SECP256K。
2.签名示例数据

priKey:::8e812436a0e3323166e1f0e8ba79e19e217b2c4a53c970d4cca0cfb1078979df
       
pubKey::04a5bb3b28466f578e6e93fbfd5f75cee1ae86033aa4bbea690e3312c087181eb366f9a1d1d6a437a9bf9fc65ec853b9fd60fa322be3997c47144eb20da658b3d1
        
hash:::159817a085f113d099d3d93c051410e9bfe043cc5c20e43aa9a083bf73660145
        
r:::38b7dac5ee932ac1bf2bc62c05b792cd93c3b4af61dc02dbb4b93dacb758123f
        
s:::08bf123eabe77480787d664ca280dc1f20d9205725320658c39c6c143fd5642d
        
v:::0

注意:签名结果应该是65字节。 r 32字节, s 32字节,v 1个字节。

3.fullnode节点收到交易后会进行验签,由hash 和 r、s、v计算出一个地址,与合约中的地址进行比较,相同则为验签通过。

示例

public static Transaction sign(Transaction transaction, ECKey myKey) {
    Transaction.Builder transactionBuilderSigned = transaction.toBuilder();
    byte[] hash = sha256(transaction.getRawData().toByteArray());
    List<Contract> listContract = transaction.getRawData().getContractList();

    for (int i = 0; i < listContract.size(); i++) {
      ECDSASignature signature = myKey.sign(hash);
      ByteString bsSign = ByteString.copyFrom(signature.toByteArray());

      //Each contract may be signed with a different private key in the future.
      transactionBuilderSigned.addSignature(bsSign);
    }
  }