美文网首页
用Substrate区块链实现UTXO功能

用Substrate区块链实现UTXO功能

作者: SeanC52111 | 来源:发表于2019-11-19 20:46 被阅读0次

    首先我们定义实现UTXO所需要的结构体:

    /// Single transaction to be dispatched
    #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
    #[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash)]
    pub struct Transaction {
        /// UTXOs to be used as inputs for current transaction
        pub inputs: Vec<TransactionInput>,
    
        /// UTXOs to be created as a result of current transaction dispatch
        pub outputs: Vec<TransactionOutput>,
    }
    

    结构体里声明了inputs, ouptuts,为UTXO结构中的输入和输出。#[...]表示一系列属性,它们可以告知Rust编译器来实现不同的功能,比如比较函数,哈希函数,序列化函数等。

    这里的inputsoutputs的类型均为存有TransactionInputTransactionOutput的Vec(向量)。下面我们来定义对应TransactionInput的结构:

    /// Single transaction input that refers to one UTXO
    #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
    #[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash)]
    pub struct TransactionInput {
        /// Reference to an UTXO to be spent
        pub parent_output: H256,
    
        /// Proof that transaction owner is authorized to spend referred UTXO
        pub signature: Signature,
    }
    

    TransactionInput中罗列了一个单独的UTXO所需要的全部信息。首先我们需要指明我们要使用哪个当前存在的UTXO,以便于之后将其花掉。最好的方法就是用哈希来充当它的标识。parent_output就存有这样的哈希。

    要花掉UTXO,所有者必须用私钥签名,之后即可用公钥进行验证。这样的证明proof被存在signature域中。

    接下来我们看TransactionOutput结构:

    /// Single transaction output to create upon transaction dispatch
    #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
    #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Hash)]
    pub struct TransactionOutput {
        /// Value associated with this output
        pub value: Value,
    
        /// Public key associated with this output. In order to spend this output
        /// owner must provide a proof by hashing whole `TransactionOutput` and
        /// signing it with a corresponding private key.
        pub pubkey: H256,
    
        /// Unique (potentially random) value used to distinguish this
        /// particular output from others addressed to the same public
        /// key with the same value. Prevents potential replay attacks.
        pub salt: u32,
    }
    

    其中,盐值salt是用来对相同的value, pubkey每次产生不同的Hash值。

    状态

    前面我们已经定义了相关的数据结构,比如如何在区块链中表示UTXO对应的交易结构。下面我们来看看如何存储这些transactions到Substrate的state db中。

    在之前的博客中 https://www.jianshu.com/p/f9a41a2fc90a
    我们知道在Substrate中进行自定义存储需要在decl_storage! macro当中定义。

    decl_storage! {
        trait Store for Module<T: Trait> as Utxo {
            /// All valid unspent transaction outputs are stored in this map.
            /// Initial set of UTXO is populated from the list stored in genesis.
            UnspentOutputs build(|config: &GenesisConfig<T>| {
                config.initial_utxo
                    .iter()
                    .cloned()
                    .map(|u| (BlakeTwo256::hash_of(&u), u))
                    .collect::<Vec<_>>()
            }): map H256 => Option<TransactionOutput>;
    
            /// Total leftover value to be redistributed among authorities.
            /// It is accumulated during block execution and then drained
            /// on block finalization.
            LeftoverTotal: Value;
    
            /// Outputs that are locked
            LockedOutputs: map H256 => Option<LockStatus<T>>;
        }
    
        add_extra_genesis {
            config(initial_utxo): Vec<TransactionOutput>;
        }
    }
    

    上述代码定义了:

    • 未花掉的output
    • 当前剩余的金额
    • 被锁定的outputs

    同时,上述代码还定义了在区块链启动得时候初始化UTXO。
    需要注意的是,区块的存储和状态的存储有很大的区别。区块的存储对于区块链节点来说是十分重要的组成部分,它被用来储存区块链中的区块。而对于状态存储来说,它是和逻辑息息相关的。它包含了所有反应当前状态的数据和关系。为了验证新接收的transactions,我们只需要关心各个参与的party的状态和资金。这也解释了为何情节点也可以验证transactions。

    逻辑

    当我们说Alice收到来自Bob的转账,实际上发生的是一些列Bob付给Alice的UTXO会被标记为已经花掉。紧接着,一些列新的UTXO(由Bob产生给Alice的)会变成有效的UTXO(可在之后被使用)。

    这就是给予UTXO转账的基本逻辑,我们在验证和分发transactions的时候需要考虑这样的逻辑。下面我们看看具体UTXO module(模块)的代码:

    decl_module! {
        pub struct Module<T: Trait> for enum Call where origin: T::Origin {
            /// Dispatch a single transaction and update UTXO set accordingly
            pub fn execute(origin, transaction: Transaction) -> Result {
                ensure_inherent(origin)?;
    
                let leftover = match Self::check_transaction(&transaction)? {
                    CheckInfo::MissingInputs(_) => return Err("all parent outputs must exist and be unspent"),
                    CheckInfo::Totals { input, output } => input - output
                };
    
                Self::update_storage(&transaction, leftover)?;
                Self::deposit_event(Event::TransactionExecuted(transaction));
    
                Ok(())
            }
    
            /// Handler called by the system on block finalization
            fn on_finalise() {
                let authorities: Vec<_> = Consensus::authorities().iter().map(|&a| a.into()).collect();
                Self::spend_leftover(&authorities);
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:用Substrate区块链实现UTXO功能

          本文链接:https://www.haomeiwen.com/subject/kokgictx.html