智能合约
交易结构
智能合约
public static UnlockScripts ProduceSingleUnlockScript(this Signature sig) => (UnlockScripts)new[] {
ScriptToken.CreateToken(sig.ToBase58()),
};
public static LockScripts ProduceSingleLockScript(this PublicKey pubKey) => (LockScripts)new[] {
ScriptToken.CreateToken(pubKey.ToBase58()),
ScriptToken.CreateToken(OpCode.CheckSignature),
};
验证交易
public static bool CanUnlock(this Transaction tran, TxInput input, TxOutput output)
{
try
{
var scripts = input.UnlockScripts + output.LockScripts;
var result = scripts.TryExecuteAsync(tran);
if (!result) return false;
}
catch (Exception)
{
return false;
}
return true;
}
private BlockHead GenerateBlock()
{
...
var minerTxOut = new TxOutput
{
LockScripts = this.MinerWallet.PublicKey.ProduceSingleLockScript(),
Value = this.BlockChain.RewardOfBlock + fee
};
var minerTx = new Transaction { Outputs = new[] { minerTxOut }, };
...
}
private bool ValidateTx(Transaction tx)
{
...
foreach (var intx in tx.InputTxs)
{
...
if (!verifyTx.CanUnlock(intx, output))
return false;
}
...
}
客户端适应
public Transaction SendMoney(Engine engine, Transaction utxo, int index, IWallet receiver, int value, int fee = 0, uint lockTime = 0)
{
var total = utxo.Outputs[index].Value;
var change = total - value - fee;
var mainOutput = new TxOutput { LockScripts = receiver.PublicKey.ProduceSingleLockScript(), Value = value };
var changeOutput = new TxOutput { LockScripts = this.PublicKey.ProduceSingleLockScript(), Value = change };
return this.SendMoney(engine, lockTime, new[] { new Utxo(utxo, index) }, mainOutput, changeOutput);
}
public Transaction SendMoney(Engine engine, uint lockTime, 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,
LockTime = lockTime,
};
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[] { (byte[])tx.GetLockHash() },
this.FindPrivateKey(utxoEnt.Tx.Outputs[utxoEnt.Index].LockScripts));
}
for (int i = 0; i < tx.InputTxs.Length; i++)
{
tx.InputTxs[i].UnlockScripts = sigList[i].ProduceSingleUnlockScript();
}
engine.AttachTx(tx);
return tx;
}
protected abstract PrivateKey FindPrivateKey(LockScripts lockScripts);
protected abstract bool ContainPubKey(LockScripts lockScripts);
public class DeterministicWallet : BaseWallet
{
protected override PrivateKey FindPrivateKey(LockScripts lockScripts)
{
var idx = this.usedPublicKeys.FindIndex(_ => lockScripts.Contains(new ScriptToken(_.ToBase58())));
if (idx == -1)
throw new KeyNotFoundException("cannot find corresponding public key");
return this.usedPrivateKeys[idx];
}
protected override bool ContainPubKey(LockScripts lockScripts)
{
return this.usedPublicKeys.Any(_ => lockScripts.Contains(new ScriptToken(_.ToBase58())));
}
}
public class SimpleWallet : BaseWallet
{
protected override PrivateKey FindPrivateKey(LockScripts lockScripts)
{
if (!lockScripts.Contains(new ScriptToken(this.PublicKey.ToBase58())))
throw new KeyNotFoundException("cannot find corresponding public key");
return this.PrivateKey;
}
protected override bool ContainPubKey(LockScripts lockScripts)
{
return lockScripts.Contains(new ScriptToken(this.PublicKey.ToBase58()));
}
}