在第一章已经学习过轻量客户端的概念,并知道了并非所有的节点都有能力储存完整的区块链, 因此对于这些被设计成运行在空间和功率受限的设备的轻量客户端, 通过简化的支付验证(SPV)的方式可以使它们在不必存储完整区块链的情况下进行工作。 轻量客户端仅仅需要下载区块头信息,而不用下载包含在每个区块中的交易信息。 由此产生的不含交易信息的区块链,大小会远远小于完整的区块链,这样便适合在受限环境上执行。 鉴于轻量客户端并不知道网络上所有交易的完整信息,其验证交易时所使用的方法略有不同, 这个方法需依赖对等的全节点“按需"提供区块链中相关部分的局部视图。
在本节中。。。。。。
public interface IWallet { string Name { get; } PrivateKey PrivateKey { get; } PublicKey PublicKey { get; } Transaction SendMoney(Engine engine, Transaction utxo, int index, IWallet receiver, int value, int fee = 0); Transaction SendMoney(Engine engine, Utxo[] utxos, params TxOutput[] outputs); void GenerateKeyPair(); Utxo[] GetUtxos(Engine engine); void SyncBlockHead(Engine engine); bool VerifyTx(Engine engine, Transaction tx); }
代码:ClassicBlockChain\Wallet\IWallet.cs
public abstract class BaseWallet : IWallet { protected ISignAlgorithm signAlgo = new ECDsaSignAlgorithm(); protected Dictionary<UInt256, BlockHead> blockHeads protected BaseWallet(string name) { this.Name = name; this.GenerateKeyPair(); } ... protected virtual void AfterKeyPairGenerated() protected abstract PrivateKey FindPrivateKey(PublicKey publicKey); protected abstract bool ContainPubKey(PublicKey publicKey); }
public Transaction SendMoney(Engine engine, Utxo[] utxos, params TxOutput[] outputs) { var inputTxs = utxos .Select(_ => new TxInput { PrevTxHash = _.Tx.Hash, PrevTxIndex = _.Index }) .ToArray(); var tx = new Transaction { InputTxs = inputTxs, Outputs = outputs, }; var sigList = new Signature[tx.InputTxs.Length]; for (int i = 0; i < tx.InputTxs.Length; i++) { var utxoEnt = utxos[i]; sigList[i] = this.signAlgo.Sign( new[] { Encoding.UTF8.GetBytes(tx.HashContent) }, this.FindPrivateKey(utxoEnt.Tx.Outputs[utxoEnt.Index].PublicKey)); } for (int i = 0; i < tx.InputTxs.Length; i++) { tx.InputTxs[i].Signature = sigList[i]; } engine.AttachTx(tx); return tx; }
public Transaction SendMoney(Engine engine, Transaction utxo, int index, IWallet receiver, int value, int fee = 0) { var total = utxo.Outputs[index].Value; var change = total - value - fee; var mainOutput = new TxOutput { PublicKey = receiver.PublicKey, Value = value }; var changeOutput = new TxOutput { PublicKey = this.PublicKey, Value = change }; return this.SendMoney(engine, new[] { new Utxo(utxo, index) }, mainOutput, changeOutput); }
public Utxo[] GetUtxos(Engine engine) { var txlist = engine.BlockChain.TxToBlockDictionary .Select(_ => engine.BlockChain.GetTx(_.Key)) .SelectMany(_ => _.Outputs.Select((txo, i) => new { tx = _, txo, i })) .Where(_ => this.ContainPubKey(_.txo.PublicKey)) .Where(_ => !engine.BlockChain.UsedTxDictionary.ContainsKey((_.tx.Hash, _.i))) .Select(_ => new Utxo(_.tx, _.i)) .ToArray(); return txlist; }
public void SyncBlockHead(Engine engine) { var blocks = engine.BlockChain.BlockHeadDictionary.ToDictionary(_ => _.Key, _ => _.Value); var newBlockHash = blocks.Select(_ => _.Key).ToArray(); var oldBlockHash = this.blockHeads.Select(_ => _.Key).ToArray(); var excepts = oldBlockHash.Except(newBlockHash).ToArray(); if (excepts.Length > 0) { Console.WriteLine($"found [{excepts.Length}] diffs in sync block"); return; } this.blockHeads = blocks; }
public bool VerifyTx(Engine engine, Transaction tx) { var (hs, flags, txnum, block) = engine.GetMerkleBlock(tx.Hash); var merkleRoot = MerkleTree.GetPartialTreeRootHash(txnum, hs, flags); if (!this.blockHeads.ContainsKey(block.Hash)) return false; var localBlock = this.blockHeads[block.Hash]; return merkleRoot == localBlock.MerkleRoot; }
public class SimpleWallet : BaseWallet { public SimpleWallet(string name) : base(name) { } }
public class DeterministicWallet : BaseWallet { private List<PublicKey> usedPublicKeys = new List<PublicKey>(); private List<PrivateKey> usedPrivateKeys = new List<PrivateKey>(); public DeterministicWallet(string name) : base(name) { } }
protected override void AfterKeyPairGenerated() { this.usedPrivateKeys.Add(this.PrivateKey); this.usedPublicKeys.Add(this.PublicKey); }
protected override PrivateKey FindPrivateKey(PublicKey publicKey) { var idx = this.usedPublicKeys.FindIndex(_ => _ == publicKey); if (idx == -1) throw new KeyNotFoundException("cannot find corresponding public key"); return this.usedPrivateKeys[idx]; }
protected override bool ContainPubKey(PublicKey publicKey) { return this.usedPublicKeys.Contains(publicKey); }
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8