What is Transaction?
Let’s take a random look at the simplest Transaction and see what a Transaction is. In block exploper after a simple query in a classic 7957 a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18 txid, as you can see, what he is.
0100000001524d288f25cada331c298e21995ad070e1d1a0793e818f2f7cfb5f6122ef3e71000000008c493046022100a59e516883459706ac2e6ed6 a97ef9788942d3c96a0108f2699fa48d9a5725d1022100f9bb4434943e87901c0c96b5f3af4e7ba7b83e12c69b1edbfe6965f933fcd17d014104e5a0 b4de6c09bd9d3f730ce56ff42657da3a7ec4798c0ace2459fb007236bc3249f70170509ed663da0300023a5de700998bfec49d4da4c66288a5837462 6c8dffffffff0180969800000000001976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac00000000Copy the code
There is a Transaction HEX, but what exactly does that mean? How to decode it, you can see more clearly.
{
hash 7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18
inputs
{
input
{
address_hash 54a28c6ba2bebdb694fe487a87e3e8ed4eab1502
previous_output
{
hash 713eef22615ffb7c2f8f813e79a0d1e170d05a99218e291c33daca258f284d52
index 0
}
script "[3046022100a59e516883459706ac2e6ed6a97ef9788942d3c96a0108f2699fa48d9a5725d1022100f9bb4434943e87901c0c96b5f3af4e7ba7b83e 12c69b1edbfe6965f933fcd17d01] [04e5a0b4de6c09bd9d3f730ce56ff42657da3a7ec4798c0ace2459fb007236bc3249f70170509ed663da0300023a5de700998bfec49d4da4c66288a 58374626c8d]"
sequence 4294967295
}
}
lock_time 0
outputs
{
output
{
address_hash 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8
script "dup hash160 [7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8] equalverify checksig"
value 10000000
}
}
version 1
}
Copy the code
A typical Bitcoin transaction consists of two parts, input and output. Input is the input to the transaction, and output is the output. First look at the input, since Bitcoin is a UTXO model, the output of one transaction is the output of another transaction. Trasaction: input has a script, output has another script, what is script?
The script in input is unlocking Script, and the script in output is locking script. Unlocking Script is a unlocking Script in the input. Because it unlocks the output of the previous transaction. Which means that while the miners were in Verify Transaction, Unlocking Script + locking Script Returns true, then the money can be spent. Let’s see what’s going on.
Unlocking Script + locking Script of a TYPICAL P2PKH Transaction. Assume that Alice has a UTXO in her NTH Transaction. She then spends it on the n+1 transaction. Unlocking Script is in the INPUT of the N +1 transaction, and locking Script is in the output of the N transaction. This point must be paid attention to.
In the figure, PubkeyHash is Alice’s public keyHash, Sig is Alice’s signature, and Pubkey is Alice’s public key. So what do I get if I run this script manually?
If you run it manually, it’s True. So then Alice can use the money. Therefore, it is clear why the script in the output is a locking script. Because this transaction locks the money in a publicKey, you can only move the money if you prove that you are the owner of the private key. In turn, the owner of this key can unlock the money by signing because he has a private key. Therefore, money is locked in this way, hence the name “Locking script”. Brilliant!
Is there another problem?
How does Miner verify that a transaction can be signed at will, such as signing a Hello World? Secondly, if the signature data can be an arbitrary data, what if hacker or other arbitrarily modifies the locking script? Hacker or others gave it to B? Is that possible? Or how to deal with it?
The first problem is that miner knows how to validate the signature by signing a transaction, or part of a transaction, or hash.
Second question, this leads to the type of sign. There are several sign hash types in Bitcoin.
SIGHASH flag | Value | Description | analogy |
---|---|---|---|
ALL | 0x01 | Signature applies to all inputs and outputs | Basic type, signed from and to |
NONE | 0x02 | Signature applies to all inputs, none of the outputs | A blank check. The payee can fill it out |
SINGLE | 0x03 | Signature applies to all inputs, none of the outputs | Check all inputs, output only one |
There are other modifiers
SIGHASH flag | Value | Description | analogy |
---|---|---|---|
ALL_ANYONECANPAY | 0x81 | Signature applies to one input and all outputs | Raise transaction, state lock |
NONE_ANYONECANPAY | 0x82 | Signature applies to one input, none of the outputs | Blank check, output whatever you want |
SINGLE_ANYONECANPAY | 0x83 | Signature applies to one input and the output with the same index number | Check all inputs, output only one |
Generally speaking, the most recent basic transaction sign hash type is ALL. Take a look at the implementation in the code.
// TODO:Remove keyPair.network matching in 4.0.0
if(keyPair.network && keyPair.network ! == network)throw new TypeError('Inconsistent network');
if(! inputs[vin])throw new Error('No input at index: ' + vin);
hashType = hashType || Transaction.SIGHASH_ALL;
if (needsOutputs(hashType)) throw new Error('Transaction needs outputs');
const input = inputs[vin];
// if redeemScript was previously provided, enforce consistency
if( input.redeemScript ! = =undefined&& redeemScript && ! input.redeemScript.equals(redeemScript) ) {throw new Error('Inconsistent redeemScript');
}
Copy the code
tx_builder
const txTmp = this.clone();
// SIGHASH_NONE: ignore all outputs? (wildcard payee)
if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) {
txTmp.outs = [];
// ignore sequence numbers (except at inIndex)
txTmp.ins.forEach((input, i) = > {
if (i === inIndex) return;
input.sequence = 0;
});
// SIGHASH_SINGLE: ignore all outputs, except at the same index?
} else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) {
// https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60
if (inIndex >= this.outs.length) return ONE;
// truncate outputs after
txTmp.outs.length = inIndex + 1;
// "blank" outputs before
for (let i = 0; i < inIndex; i++) {
txTmp.outs[i] = BLANK_OUTPUT;
}
// ignore sequence numbers (except at inIndex)
txTmp.ins.forEach((input, y) = > {
if (y === inIndex) return;
input.sequence = 0;
});
}
// SIGHASH_ANYONECANPAY: ignore inputs entirely?
if (hashType & Transaction.SIGHASH_ANYONECANPAY) {
txTmp.ins = [txTmp.ins[inIndex]];
txTmp.ins[0].script = ourScript;
// SIGHASH_ALL: only ignore input scripts, leave all the outputs
} else {
// "blank" others input scripts
txTmp.ins.forEach(input= > {
input.script = EMPTY_SCRIPT;
});
txTmp.ins[inIndex].script = ourScript;
}
// serialize and hash
const buffer: Buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4);
buffer.writeInt32LE(hashType, buffer.length - 4);
txTmp.__toBuffer(buffer, 0.false);
Copy the code
tx_build_sign
private __byteLength(_ALLOW_WITNESS: boolean): number {
const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses();
return (
(hasWitnesses ? 10 : 8) +
varuint.encodingLength(this.ins.length) +
varuint.encodingLength(this.outs.length) +
this.ins.reduce((sum, input) = > {
return sum + 40 + varSliceSize(input.script);
}, 0) +
this.outs.reduce((sum, output) = > {
return sum + 8 + varSliceSize(output.script);
}, 0) +
(hasWitnesses
? this.ins.reduce((sum, input) = > {
return sum + vectorSize(input.witness);
}, 0)
: 0)); }Copy the code
tx, outs
As you can see from the above code implementation, the default hashType is ALL, so the above problem can be solved in this way, but the various forms of hashType can be used to achieve different functions.
Check out unlocking Scirpt’s signature.
3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863 ea8f53982c09db8f6e381301Copy the code
The signature is in DER format.
-
0x30 — Indicating the start of a DER sequence
-
0x45 — The Length of the Sequence (69 bytes)
-
0 x02 – an integer value follows
-
0x21 — The Length of the INTEGER (33 bytes)
-
R – 00884 d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb
-
0 x02 – another integer follows
-
0x20 — The length of the INTEGER (32 bytes)
-
S – 4 b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813
-
A suffix (0x01) indicating the type of hash used (SIGHASH_ALL)