commit
d1e8109a99
142
docs/Script.md
142
docs/Script.md
|
@ -1 +1,143 @@
|
||||||
# Script
|
# Script
|
||||||
|
|
||||||
|
All bitcoin transactions have scripts embedded into its inputs and outputs.
|
||||||
|
The scripts use a very simple programming language, which is evaluated from
|
||||||
|
left to right using a stack. The language is designed such that it guarantees
|
||||||
|
all scripts will execute in a limited amount of time (it is not Turing-Complete).
|
||||||
|
|
||||||
|
When a transaction is validated, the input scripts are concatenated with the output
|
||||||
|
scripts and evaluated. To be valid, all transaction scripts must evaluate to true.
|
||||||
|
A good analogy for how this works is that the output scripts are puzzles that specify
|
||||||
|
in which conditions can those bitcoins be spent. The input scripts provide the correct
|
||||||
|
data to make those output scripts evaluate to true.
|
||||||
|
|
||||||
|
|
||||||
|
For more detailed information about the bitcoin scripting language, check the
|
||||||
|
online reference: https://en.bitcoin.it/wiki/Script
|
||||||
|
|
||||||
|
The `Script` object provides an interface to construct, parse, and identify bitcoin
|
||||||
|
scripts. It also gives simple interfaces to create most common script types. This class
|
||||||
|
is useful if you want to create custom input or output scripts. In other case,
|
||||||
|
you should probably use `Transaction`.
|
||||||
|
|
||||||
|
|
||||||
|
## Script creation
|
||||||
|
|
||||||
|
Here's how to use `Script` to create the five most common script types:
|
||||||
|
|
||||||
|
### Pay to Public Key Hash (p2pkh)
|
||||||
|
|
||||||
|
This is the most commonly used transaction output script. It's used to pay to
|
||||||
|
a bitcoin address (a bitcoin address is a public key hash encoded in base58check)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// create a new p2pkh paying to a specific address
|
||||||
|
var address = Address.fromString('1NaTVwXDDUJaXDQajoa9MqHhz4uTxtgK14');
|
||||||
|
var s = Script.buildPublicKeyHashOut(address);
|
||||||
|
console.log(s.toString());
|
||||||
|
// 'OP_DUP OP_HASH160 20 0xecae7d092947b7ee4998e254aa48900d26d2ce1d OP_EQUALVERIFY OP_CHECKSIG'
|
||||||
|
```
|
||||||
|
### Pay to Public Key (p2pk)
|
||||||
|
|
||||||
|
Pay to public key scripts are a simplified form of the p2pkh,
|
||||||
|
but aren’t commonly used in new transactions anymore, because p2pkh scripts are
|
||||||
|
more secure (the public key is not revealed until the output is spent).
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// create a new p2pk paying to a specific public key
|
||||||
|
var pubkey = new PublicKey('022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da');
|
||||||
|
var s = Script.buildPublicKeyOut(pubkey);
|
||||||
|
console.log(s.toString());
|
||||||
|
// '33 0x022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da OP_CHECKSIG'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pay to Multisig (p2ms)
|
||||||
|
|
||||||
|
Multisig outputs allow to share control of bitcoins between several keys. When creating
|
||||||
|
the script, one specifies the public keys that control the funds, and how many of those
|
||||||
|
keys are required to sign off spending transactions to be valid. An output with N public keys
|
||||||
|
of which M are required is called an m-of-n output (For example, 2-of-3, 3-of-5, 4-of-4, etc.)
|
||||||
|
|
||||||
|
Note that regular multisig outputs are rarely used nowadays. The best practice
|
||||||
|
is to use a p2sh multisig output (See Script#toScriptHashOut()).
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// create a new 2-of-3 multisig output from 3 given public keys
|
||||||
|
var pubkeys = [
|
||||||
|
new PublicKey('022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da'),
|
||||||
|
new PublicKey('03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9'),
|
||||||
|
new PublicKey('021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18'),
|
||||||
|
];
|
||||||
|
var m = 2;
|
||||||
|
var s = Script.buildMultisigOut(pubkeys, m);
|
||||||
|
console.log(s.toString());
|
||||||
|
// 'OP_2 33 0x022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da 33 0x03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9 33 0x021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18 OP_3 OP_CHECKMULTISIG'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pay to Script Hash (p2sh)
|
||||||
|
|
||||||
|
Pay to script hash outputs are scripts that contain the hash of another script, called redeemScript.
|
||||||
|
To spend bitcoins sent in a p2sh output, the spending transaction must provide a script
|
||||||
|
matching the script hash and data which makes the script evaluate to true.
|
||||||
|
This allows to defer revealing the spending conditions to the moment of spending. It also
|
||||||
|
makes it possible for the receiver to set the conditions to spend those bitcoins.
|
||||||
|
|
||||||
|
Most multisig transactions today use p2sh outputs where the redeemScript is a multisig output.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// create a p2sh multisig output
|
||||||
|
var pubkeys = [
|
||||||
|
new PublicKey('022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da'),
|
||||||
|
new PublicKey('03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9'),
|
||||||
|
new PublicKey('021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18'),
|
||||||
|
];
|
||||||
|
var redeemScript = Script.buildMultisigOut(pubkeys, 2);
|
||||||
|
var s = redeemScript.toScriptHashOut();
|
||||||
|
console.log(s.toString());
|
||||||
|
// 'OP_HASH160 20 0x620a6eeaf538ec9eb89b6ae83f2ed8ef98566a03 OP_EQUAL'
|
||||||
|
```
|
||||||
|
### Data output
|
||||||
|
|
||||||
|
Data outputs are used to push data into the blockchain. Up to 40 bytes can be pushed
|
||||||
|
in a standard way, but more data can be used, if a miner decides to accept the transaction.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var data = 'hello world!!!';
|
||||||
|
var s = Script.buildDataOut(data);
|
||||||
|
console.log(s.toString());
|
||||||
|
// 'OP_RETURN 14 0x68656c6c6f20776f726c64212121'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom scripts
|
||||||
|
|
||||||
|
To create a custom `Script` instance, you must rely on the lower-level methods `add`
|
||||||
|
and `prepend`. Both methods accept the same parameter types, and insert an opcode or
|
||||||
|
data at the beginning (`prepend`) or end (`add`) of the `Script`.
|
||||||
|
|
||||||
|
```
|
||||||
|
var s = Script()
|
||||||
|
.add('OP_IF') // add an opcode by name
|
||||||
|
.prepend(114) // add OP_2SWAP by code
|
||||||
|
.add(new Opcode('OP_NOT')) // add an opcode object
|
||||||
|
.add(new Buffer('bacacafe', 'hex')) // add a data buffer
|
||||||
|
console.log(s.toString());
|
||||||
|
// 'OP_2SWAP OP_IF OP_NOT 4 0xbacacafe'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Script parsing and identification
|
||||||
|
|
||||||
|
`Script` has an easy interface to parse raw scripts from the newtwork or bitcoind,
|
||||||
|
and to extract useful information.
|
||||||
|
An illustrative example (for more options check the API reference)
|
||||||
|
```javascript
|
||||||
|
var raw_script = new Buffer('5221022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da2103e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e921021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc1853ae', 'hex');
|
||||||
|
var s = new Script(raw_script);
|
||||||
|
console.log(s.toString());
|
||||||
|
// 'OP_2 33 0x022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da 33 0x03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9 33 0x021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18 OP_3 OP_CHECKMULTISIG'
|
||||||
|
|
||||||
|
s.isPublicKeyHashOut() // false
|
||||||
|
s.isScriptHashOut() // false
|
||||||
|
s.isMultisigOut() // true
|
||||||
|
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue