Manuel Araoz
10 years ago
1 changed files with 142 additions and 0 deletions
@ -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) |
||||
|
``` |
||||
|
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