Skip to content

Transaction

TowardsFree edited this page Mar 7, 2019 · 9 revisions

交易

概述

源文件
transaction.h destination.h CTransaction CTxOutPoint CTxIn CDestination CTxOutput

交易的数据结构


FnFn链采用与比特币一致的 UTXO 模型记录交易,弱化了账户的概念。CTransaction类表示一笔交易,类成员有如下字段:

    uint16 nVersion;  //版本号,目前交易版本为 0x0001
    uint16 nType;     // 类型, 区分公钥地址交易、模板地址交易、即时业务交易和跨分支交易
    uint32 nLockUntil; // 交易冻结至高度为 nLockUntil 区块
    uint256 hashAnchor; // 交易有效起始区块 HASH
    std::vector<CTxIn> vInput; // 前序交易输出列表,包含前序交易 ID 和输出点序号
    CDestination sendTo; // 输出地址
    int64 nAmount;       // 输出金额
    int64 nTxFee;        // 网络交易费 
    std::vector<uint8> vchData; // 输出参数(模板地址参数、跨分支交易共轭交易)
    std::vector<uint8> vchSig;   // 交易签名
  1. nType字段表示此交易的类型,以enum class的方式表示:
    enum 
    {
        TX_TOKEN    = 0x0000,  // 常规的代币交易
        TX_CERT     = 0xff00,  // 委托交易
        TX_GENESIS  = 0x0100,  // 创世区块的coinbase交易
        TX_STAKE    = 0x0200,  // DPOS共识出块的coinbase交易
        TX_WORK     = 0x0300,  // POw共识出块的coinbase交易
    };
  1. hashAnchor字段,用于指明当前交易适用于特定一个或多个分支。
  2. vInput,就是UTXO模型中的多个交易的输入,也就是资金来源,就是前序交易的UTXO输出,用(PreTxId,nIndex)二元结构表示一个输入或是前序交易的输出。
  3. sendTo, 输出地址,也就是资金的去向。可以简单理解为钱包地址或者模板ID,但是实际上是一个公钥地址+公钥前缀(0x01)或模板ID+模板前缀(0x02),因为钱包的地址是通过对钱包公钥作Hash和最后做一道Base32编码转换成的可读的文本表示。
  4. nAmount,输出金额,也就是该交易所有输出的总计(合)。
  5. nTxFee,交易费,相当于给矿工的钱,最后需要打包到Block中的txMint字段中

注意: 输入输出中隐含了找零机制,关系是 : 找零 = vInput - nAmount - nTxFee

  1. vchData, 输出参数(模板地址参数、跨分支交易共轭交易) 待定,暂时不很清楚详细用途,白皮书看不明白。模板很类似BTC中的脚本
  2. vchSig, 交易签名

涉及到交易相关的类的关系及方法


类的关系

  • CTxIn 表示交易的一条输入,对应前序交易的一个UTXO输出,其实CTxIn类就以复合方式(没用继承)复用了CTxOutPoint类
  • CDestination 表示交易的一个输出地址
  • CTxOutPoint 表示一个输出,以(wallet_pubkey,nIndex)这样的二元结构表示一个输出
  • CTxOutput 表示一个输出所输出的Detail,比如输出额度(nAmount),输出地址(CDestination)等。
  • CTransaction表示一个交易,一个交易可能有多个输入和多个输出
  • CTxUnspent 表示一个UTXO, 继承了CTxOutPoint类,以复合方式复用了CTxOutput类,也就是输出的Detail
  • CAssembledTx 表示一个已经被打包进区块的交易,继承了CTransaction。
  • CTxIndex 表示一个交易的索引,把一个交易与本地节点存储的文件和偏移关联上,用于快速定位查找块文件中的交易

交易相关类的方法

CTransaction类的主要方法
  1. 设置交易为空
void SetNull()
  1. 判断交易是否为空,通过输入是否为空和输出地址是否为空作为判断依据
bool IsNull() const;
  1. 判断交易类型是否是矿机器交易
bool IsMintTx() const;
  1. 得到交易类型的可读的文本表示
std::string GetTypeString() const
  1. 得到交易的Hash,对交易的所有二进制数据作Hash
     uint256 GetHash() const
    {
        walleve::CWalleveBufStream ss;
        ss << (*this);
        return multiverse::crypto::CryptoHash(ss.GetData(),ss.GetSize());
    }
  1. 得到签名Hash,对除去vchSig字段以外的所有字段Hash。
    uint256 GetSignatureHash() const
    {
        walleve::CWalleveBufStream ss;
        ss << nVersion << nType << nLockUntil << hashAnchor << vInput << sendTo << nAmount << nTxFee << vchData;
        return multiverse::crypto::CryptoHash(ss.GetData(),ss.GetSize());
    }
  1. 得到找零的金额。
    int64 GetChange(int64 nValueIn) const
    {
        return (nValueIn - nAmount - nTxFee);
    }
CTxOutput类的主要方法
  1. 清空输出
void SetNull();
  1. 判断输出是否为空。
bool IsNull() const ;
  1. 判断输出是否被锁住了。
bool IsLocked(int nBlockHeight) const { return (nBlockHeight < nLockUntil); } 

如果传入的块高度比冻结高度小,那么就被锁住了。

  1. 把输出转换为字符串的形式
std::string ToString() const ;

输出的字符串形式为以下形式(输出地址的十六进制字符串,输出的额度,冻结至区块高度):

TxOutput : (12a2b124c214ccdef , 0.1  ,  25231 )   
CAssembledTx类的主要方法
  1. 设置交易为空
 void SetNull();
  1. 计算找零
    int64 GetChange() const
    {
        return (nValueIn - nAmount - nTxFee);
    }
  1. 通过输出的序号得到相应的输出
    const CTxOutput GetOutput(int n=0) const
    {
        if (n == 0)
        {
            return CTxOutput(sendTo,nAmount,nLockUntil);
        }
        else if (n == 1)
        {
            return CTxOutput(destIn,GetChange(),0);
        }
        return CTxOutput();
    }

输入参数为0的时候得到的是发送给别的钱包的输出。 输入参数为1的时候得到的是给自己钱包找零的输出。 如果输入参数为其他,那么构造的是空的输出。

CTxContxt类的主要方法
  1. 获取交易的所有输入金额总和
     int64 GetValueIn() const
    {
        int64 nValueIn = 0;
        for (int i = 0;i < vInputValue.size();i++)
        {
            nValueIn += vInputValue[i].first;
        }
        return nValueIn;
    }
整理者 日期
Shaohan Chen to be continue

Clone this wiki locally