      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134

    //! Script builder

    use bytes::Bytes;
    use {Opcode, Script, Num};
    use keys::AddressHash;

    /// Script builder
    #[derive(Default)]
    pub struct Builder {
    	data: Bytes,
    }

    impl Builder {
    	/// Builds p2pkh script pubkey
    	pub fn build_p2pkh(address: &AddressHash) -> Script {
    		Builder::default()
    			.push_opcode(Opcode::OP_DUP)
    			.push_opcode(Opcode::OP_HASH160)
    			.push_bytes(&**address)
    			.push_opcode(Opcode::OP_EQUALVERIFY)
    			.push_opcode(Opcode::OP_CHECKSIG)
    			.into_script()
    	}

    	/// Builds p2sh script pubkey
    	pub fn build_p2sh(address: &AddressHash) -> Script {
    		Builder::default()
    			.push_opcode(Opcode::OP_HASH160)
    			.push_bytes(&**address)
    			.push_opcode(Opcode::OP_EQUAL)
    			.into_script()
    	}

    	/// Builds op_return script
    	pub fn build_nulldata(bytes: &[u8]) -> Script {
    		Builder::default()
    			.push_opcode(Opcode::OP_RETURN)
    			.push_bytes(bytes)
    			.into_script()
    	}

    	/// Pushes opcode to the end of script
    	pub fn push_opcode(mut self, opcode: Opcode) -> Self {
    		self.data.push(opcode as u8);
    		self
    	}

    	/// Appends bool push operation to the end of script
    	pub fn push_bool(mut self, value: bool) -> Self {
    		if value {
    			self.data.push(Opcode::OP_1 as u8);
    		} else {
    			self.data.push(Opcode::OP_0 as u8);
    		}
    		self
    	}

    	/// Appends num push operation to the end of script
    	pub fn push_num(self, num: Num) -> Self {
    		self.push_data(&num.to_bytes())
    	}

    	/// Appends bytes push operation to the end od script
    	pub fn push_bytes(mut self, bytes: &[u8]) -> Self {
    		let len = bytes.len();
    		if len < 1 || len > 75 {
    			panic!(format!("Canot push {} bytes", len));
    		}

    		let opcode: Opcode = Opcode::from_u8(((Opcode::OP_PUSHBYTES_1 as usize) + len - 1) as u8)
    			.expect("value is within [OP_PUSHBYTES_1; OP_PUSHBYTES_75] interval; qed");
    		self.data.push(opcode as u8);
    		self.data.extend_from_slice(bytes);
    		self
    	}

    	/// Appends data push operation to the end of script
    	pub fn push_data(mut self, data: &[u8]) -> Self {
    		let len = data.len();
    		if len < Opcode::OP_PUSHDATA1 as usize {
    			self.data.push(len as u8);
    		} else if len < 0x100 {
    			self.data.push(Opcode::OP_PUSHDATA1 as u8);
    			self.data.push(len as u8);
    		} else if len < 0x10000 {
    			self.data.push(Opcode::OP_PUSHDATA2 as u8);
    			self.data.push(len as u8);
    			self.data.push((len >> 8) as u8);
    		} else if len < 0x1_0000_0000 {
    			self.data.push(Opcode::OP_PUSHDATA4 as u8);
    			self.data.push(len as u8);
    			self.data.push((len >> 8) as u8);
    			self.data.push((len >> 16) as u8);
    			self.data.push((len >> 24) as u8);
    		} else {
    			panic!("Cannot push more than 0x1_0000_0000 bytes");
    		}

    		self.data.extend_from_slice(data);
    		self
    	}

    	/// Appends `OP_RETURN` operation to the end of script
    	pub fn return_bytes(mut self, bytes: &[u8]) -> Self {
    		let len = bytes.len();
    		if len < 1 || len > 75 {
    			panic!(format!("Canot push {} bytes", len));
    		}

    		let opcode: Opcode = Opcode::from_u8(((Opcode::OP_PUSHBYTES_1 as usize) + len - 1) as u8)
    			.expect("value is within [OP_PUSHBYTES_1; OP_PUSHBYTES_75] interval; qed");

    		self.data.push(Opcode::OP_RETURN as u8);
    		self.data.push(opcode as u8);
    		self.data.extend_from_slice(bytes);
    		self
    	}

    	/// Pushes invalid opcode to the end of script
    	pub fn push_invalid_opcode(mut self) -> Self {
    		self.data.push(0xff);
    		self
    	}

    	/// Builds final script
    	pub fn into_script(self) -> Script {
    		Script::new(self.data)
    	}

    	/// Builds final script bytes
    	pub fn into_bytes(self) -> Bytes {
    		self.data
    	}
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g. `str,u8` or `String,struct:Vec,test`)