# 合约和用户地址介绍 在区块链上,通常会有一个地址,作为用户或者合约在链上的唯一标识符。为了保证地址的唯一性,地址一般由哈希计算得到。一般来说,用户的地址根据公钥计算得到,而智能合约的地址由区块链自动生成。 ## 计算方式 在ChainMaker上,用户地址也是根据用户的公钥计算得到的,但合约地址,可以由链自动生成,也可以根据用户的合约名计算得到。且对于合约来说,ChainMaker支持合约名与合约地址两种方式调用。对于任意类型的合约,包括evm、wasmer、wxvm等等,ChainMaker部署合约时,都会将用户提供的合约名计算为合约地址,并在合约部署成功后将合地址放入contract对象内返回,用户反序列化contract对象就得到该合约的地址。 对于ChainMaker来说,当前支持以下三种地址类型: - **CHAINMAKER** 此地址格式为20字节数组,但一般会将其转换为可展示的16进制字符串,转换后长度为40字节,例如:`ce244336a16f64c5b6b27feae28a5ebd270be8ee`。CHAINMAKER对于公钥模式的用户来说,由于计算SKI稍显复杂,现已不推荐使用。 - 用户地址——根据用户的SKI(SubjectKeyId)计算keccak256哈希,然后截取哈希值的后20字节,对外展示时,会再转换为十六进制字符串形式; - 合约地址——根据合约名计算keccak256哈希,然后截取哈希值的后20字节,对外展示时,会再转换为十六进制字符串形式。 - **ZXL** 过期,不建议使用 - **ETHEREUM** 此地址格式也是20字节数组,转换为可展示的16进制字符串后,一般会加一个”0x“前缀,长度也变成了42字节,例如:`0x7cf146966856b4899b4f25f169d81176d0942050`,但”0x“前缀非必须,可加可不加。 - 用户地址——对用户公钥序列化后,计算keccak256哈希,然后截取哈希值的后20字节,对外展示时,会再转换为十六进制字符串形式; - 合约地址——根据合约名计算keccak256哈希,然后截取哈希值的后20字节,对外展示时,会再转换为十六进制字符串形式。 ETHEREUM与CHAINMAKER非常相似,尤其对于合约地址,两者的参数和哈希算法都是相同的。但对于用户地址稍有不同,主要是地址的计算参数,ETHEREUM是序列化后的公钥,而CHAINMAKER为SKI,哈希算法仍然是相同的。 ETHEREUM地址类型的优点是兼容以太坊地址类型,而且,也是ChainMaker的默认地址类型。 ## 版本历史 在长安链2.3.0版本之前,除了solidity合约外,其他类型的合约不支持地址,只有合约名,且solidity的合约名本身就是地址,非地址类型的字符串无法作为合约名使用。此外,合约地址只支持**CHAINMAKER**和**ZXL**两种类型。 自2.3.0版本开始,长安链内所有类型的合约都已支持地址功能,且地址和合约名分开,成为合约的不同属性,用户可以通过合约名调用合约,也可以通过地址调用。此外,还添加了新的地址类型**ETHEREUM**,且长安链所有类型合约,都支持以上三种地址类型。 ## 配置 在ChainMaker内,地址类型可以通过配置文件chainconfig/bc.yml内的addr_type字段指定,配置为0,是CHAINMAKER类型,1为ZXL类型,2为EHEREUM类型,默认配置类型为2,如下所示。 ***chainconfig/bc.yml配置地址类型的片段*** ```shell ...... # 虚拟机配置 vm: addr_type: 2 #0:chainmaker, 1:zxl, 2:ethereum # 虚拟机支持列表 support_list: ...... ``` ## 计算接口 对于地址的计算,ChainMaker为开发者提供了统一的计算接口,这些接口统一放在了utils模块下的address.go原文件内(gitlab链接:https://git.chainmaker.org.cn/chainmaker/utils/-/blob/master/address.go),开发者可通过导入该模块,并调用对应的接口计算地址,以保证接口计算的一致性。以下表格为地址计算接口展示。 ***utils/address.go下提供的地址计算接口*** | 接口 | 功能 | | ------------------------------------------------------------ | ---------------------------------------- | | func GenerateAddrStr(data []byte, addrType config.AddrType) (string, err) | 根据数据计算十六进制字符串类型的地址 | | func GenerateAddrInt(data []byte, addrType config.AddrType) (big.Int, err) | 根据数据计算big.Int类型的地址 | | func PkToAddrStr(pk crypto.PublicKey, addrType config.AddrType, hashType crypto.HashType)(string, err) | 根据公钥计算16进制字符串类型的地址 | | func PkToAddrInt(pk crypto.PublicKey, addrType config.AddrType, hashType crypto.HashType)(big.Int, err) | 根据公钥计算big.Int类型的地址 | | func CertToAddrStr(cert *x509.Certificate, addrType config.AddrType) (string, err) | 根据证书计算16进制字符串类型的地址 | | func CertToAddrInt(cert *x509.Certificate, addrType config.AddrType)(big.Int, err) | 根据证书计算big.Int类型的地址 | | func GetStrAddrFromMember(member protocol.Member, addrType config.AddrType) (string, err) | 根据member类型计算16进制字符串类型的地址 | | func GetIntAddrFromMember(member protocol.Member, addrType config.AddrType) (big.Int, err) | 根据member类型计算big.Int类型的地址 |