lib/bitcoin.rb in bitcoin-ruby-0.0.5 vs lib/bitcoin.rb in bitcoin-ruby-0.0.6
- old
+ new
@@ -2,12 +2,12 @@
# Bitcoin Utils and Network Protocol in Ruby.
require 'digest/sha2'
require 'digest/rmd160'
require 'openssl'
+require 'securerandom'
-
module Bitcoin
autoload :Connection, 'bitcoin/connection'
autoload :Protocol, 'bitcoin/protocol'
autoload :P, 'bitcoin/protocol'
@@ -19,10 +19,11 @@
autoload :Config, 'bitcoin/config'
autoload :Builder, 'bitcoin/builder'
autoload :Validation, 'bitcoin/validation'
autoload :Namecoin, 'bitcoin/namecoin'
+ autoload :Litecoin, 'bitcoin/litecoin'
module Network
autoload :ConnectionHandler, 'bitcoin/network/connection_handler'
autoload :CommandHandler, 'bitcoin/network/command_handler'
autoload :CommandClient, 'bitcoin/network/command_client'
@@ -126,10 +127,15 @@
def pubkey_to_address(pubkey)
hash160_to_address( hash160(pubkey) )
end
+ def pubkeys_to_p2sh_multisig_address(m, *pubkeys)
+ redeem_script = Bitcoin::Script.to_p2sh_multisig_script(m, *pubkeys).last
+ return Bitcoin.hash160_to_p2sh_address(Bitcoin.hash160(redeem_script.hth)), redeem_script
+ end
+
def int_to_base58(int_val, leading_zero_bytes=0)
alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
base58_val, base = '', alpha.size
while int_val > 0
int_val, remainder = int_val.divmod(base)
@@ -226,10 +232,27 @@
h = "%08x%08x%08x%064s%064s%08x" %
[nonce, bits, time, mrkl_root, prev_block, ver]
bitcoin_hash(h)
end
+ def litecoin_hash(hex)
+ bytes = [hex].pack("H*").reverse
+ begin
+ require "scrypt" unless defined?(::SCrypt)
+ hash = SCrypt::Engine.__sc_crypt(bytes, bytes, 1024, 1, 1, 32)
+ rescue LoadError
+ hash = Litecoin::Scrypt.scrypt_1024_1_1_256_sp(bytes)
+ end
+ hash.reverse.unpack("H*")[0]
+ end
+
+ def block_scrypt_hash(prev_block, mrkl_root, time, bits, nonce, ver)
+ h = "%08x%08x%08x%064s%064s%08x" %
+ [nonce, bits, time, mrkl_root, prev_block, ver]
+ litecoin_hash(h)
+ end
+
# get merkle tree for given +tx+ list.
def hash_mrkl_tree(tx)
return [nil] if tx != tx.uniq
chunks = [ tx.dup ]
while chunks.last.size >= 2
@@ -304,17 +327,15 @@
raise "invalid address" unless valid_address?(address)
raise "malformed base64 encoding" unless signature
raise "malformed signature" unless signature.bytesize == 65
pubkey = Bitcoin::OpenSSL_EC.recover_compact(hash, signature)
pubkey_to_address(pubkey) == address if pubkey
- rescue Exception => ex
+ rescue => ex
p [ex.message, ex.backtrace]; false
end
- RETARGET_INTERVAL = 2016
-
# block count when the next retarget will take place.
def block_next_retarget(block_height)
(block_height + (RETARGET_INTERVAL-block_height.divmod(RETARGET_INTERVAL).last)) - 1
end
@@ -407,23 +428,25 @@
autoload :OpenSSL_EC, "bitcoin/ffi/openssl"
@network = :bitcoin
def self.network
- NETWORKS[@network]
+ # Store the copy of network options so we can modify them in tests without breaking the defaults
+ @network_options ||= NETWORKS[@network].dup
end
def self.network_name
@network
end
def self.network_project
@network_project
end
- def self.network= name
+ def self.network=(name)
raise "Network descriptor '#{name}' not found." unless NETWORKS[name.to_sym]
+ @network_options = nil # clear cached parameters
@network = name.to_sym
@network_project = network[:project] rescue nil
Bitcoin::Namecoin.load if namecoin?
@network
end
@@ -431,17 +454,43 @@
[:bitcoin, :namecoin, :litecoin, :freicoin].each do |n|
instance_eval "def #{n}?; network_project == :#{n}; end"
end
- CENT = 1_000_000
- COIN = 100_000_000
+ # maximum size of a block (in bytes)
MAX_BLOCK_SIZE = 1_000_000
+
+ # soft limit for new blocks
MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2
- MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50
+
+ # maximum number of signature operations in a block
+ MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE / 50
+
+ # maximum number of orphan transactions to be kept in memory
MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100
+ # Threshold for lock_time: below this value it is interpreted as block number, otherwise as UNIX timestamp.
+ LOCKTIME_THRESHOLD = 500000000 # Tue Nov 5 00:53:20 1985 UTC
+
+ # maximum integer value
+ UINT32_MAX = 0xffffffff
+ INT_MAX = 0xffffffff # deprecated name, left here for compatibility with existing users.
+
+ # number of confirmations required before coinbase tx can be spent
+ COINBASE_MATURITY = 100
+
+ # interval (in blocks) for difficulty retarget
+ RETARGET_INTERVAL = 2016
+ RETARGET = 2016 # deprecated constant
+
+
+ # interval (in blocks) for mining reward reduction
+ REWARD_DROP = 210_000
+
+ CENT = 1_000_000
+ COIN = 100_000_000
+
MIN_FEE_MODE = [ :block, :relay, :send ]
NETWORKS = {
:bitcoin => {
@@ -452,14 +501,18 @@
:privkey_version => "80",
:default_port => 8333,
:protocol_version => 70001,
:coinbase_maturity => 100,
:retarget_interval => 2016,
- :retarget_time => 1209600, # 2 weeks
+ :retarget_time => 1209600, # 2 weeks
+ :target_spacing => 600, # block interval
:max_money => 21_000_000 * COIN,
:min_tx_fee => 10_000,
:min_relay_tx_fee => 10_000,
+ :free_tx_bytes => 1_000,
+ :dust => CENT,
+ :per_dust_fee => false,
:dns_seeds => [
"seed.bitcoin.sipa.be",
"dnsseed.bluematt.me",
"dnsseed.bitcoin.dashjr.org",
"bitseed.xf2.org",
@@ -482,13 +535,42 @@
168000 => "000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763",
193000 => "000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317",
210000 => "000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e",
216116 => "00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e",
225430 => "00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932",
+ 290000 => "0000000000000000fa0b2badd05db0178623ebf8dd081fe7eb874c26e27d0b3b",
+ 300000 => "000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254",
+ 305000 => "0000000000000000142bb90561e1a907d500bf534a6727a63a92af5b6abc6160",
}
},
+ :regtest => {
+ :project => :bitcoin,
+ :magic_head => "\xFA\xBF\xB5\xDA",
+ :address_version => "6f",
+ :p2sh_version => "c4",
+ :privkey_version => "ef",
+ :default_port => 18444,
+ :max_money => 21_000_000 * COIN,
+ :dns_seeds => [ ],
+ :genesis_hash => "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206",
+ :proof_of_work_limit => (1<<255) - 1,
+ :alert_pubkeys => ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
+ :known_nodes => [],
+ :checkpoints => {},
+ :coinbase_maturity => 100,
+ :retarget_interval => 2016,
+ :retarget_time => 1209600, # 2 weeks
+ :target_spacing => 600, # block interval
+ :max_money => 21_000_000 * COIN,
+ :min_tx_fee => 10_000,
+ :min_relay_tx_fee => 10_000,
+ :free_tx_bytes => 1_000,
+ :dust => CENT,
+ :per_dust_fee => false,
+ },
+
:testnet => {
:project => :bitcoin,
:magic_head => "\xFA\xBF\xB5\xDA",
:address_version => "6f",
:p2sh_version => "c4",
@@ -502,13 +584,17 @@
:known_nodes => [],
:checkpoints => {},
:coinbase_maturity => 100,
:retarget_interval => 2016,
:retarget_time => 1209600, # 2 weeks
+ :target_spacing => 600, # block interval
:max_money => 21_000_000 * COIN,
:min_tx_fee => 10_000,
:min_relay_tx_fee => 10_000,
+ :free_tx_bytes => 1_000,
+ :dust => CENT,
+ :per_dust_fee => false,
},
:testnet3 => {
:project => :bitcoin,
:magic_head => "\x0b\x11\x09\x07",
@@ -518,52 +604,62 @@
:default_port => 18333,
:protocol_version => 70001,
:coinbase_maturity => 100,
:retarget_interval => 2016,
:retarget_time => 1209600, # 2 weeks
+ :target_spacing => 600, # block interval
:max_money => 21_000_000 * COIN,
:min_tx_fee => 10_000,
+ :no_difficulty => true, # no good. add right testnet3 difficulty calculation instead
:min_relay_tx_fee => 10_000,
+ :free_tx_bytes => 1_000,
+ :dust => CENT,
+ :per_dust_fee => false,
:dns_seeds => [
"testnet-seed.bitcoin.petertodd.org",
"testnet-seed.bluematt.me",
],
:genesis_hash => "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943",
- :proof_of_work_limit => 0x1d07fff8,
+ :proof_of_work_limit => 0x1d00ffff,
:alert_pubkeys => ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
:known_nodes => [],
:checkpoints => {
# 542 contains invalid transaction
542 => "0000000083c1f82cf72c6724f7a317325806384b06408bce7a4327f418dfd5ad",
71018 => "000000000010dd93dc55541116b2744eb8f4c3b706df6e8512d231a03fb9e435",
+ 200000 => "0000000000287bffd321963ef05feab753ebe274e1d78b2fd4e2bfe9ad3aa6f2",
+ 250000 => "0000000005910c146e4e8d71e8aa6617393738a9794b43cf113076dbaf08460b",
}
},
:litecoin => {
:project => :litecoin,
:magic_head => "\xfb\xc0\xb6\xdb",
:address_version => "30",
:p2sh_version => "05",
:privkey_version => "b0",
:default_port => 9333,
- :protocol_version => 60002,
+ :protocol_version => 70002,
:max_money => 84_000_000 * COIN,
- :min_tx_fee => 2_000_000,
+ :min_tx_fee => 100_000, # 0.001 LTC
+ :min_relay_tx_fee => 100_000, # 0.001 LTC
+ :free_tx_bytes => 5_000,
+ :dust => CENT / 10,
+ :per_dust_fee => true,
:coinbase_maturity => 100,
:retarget_interval => 2016,
:retarget_time => 302400, # 3.5 days
- :min_relay_tx_fee => 1_000_000,
:dns_seeds => [
"dnsseed.litecointools.com",
"dnsseed.litecoinpool.org",
"dnsseed.ltc.xurious.com",
"dnsseed.koin-project.com",
"dnsseed.weminemnc.com",
],
:genesis_hash => "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2",
:proof_of_work_limit => 0,
- :alert_pubkeys => [],
+ :alert_pubkeys => ["040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"],
:known_nodes => [],
:checkpoints => {
1 => "80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f",
2 => "13957807cdd1d02f993909fa59510e318763f99a506c4c426e3b254af09f40d7",
1500 => "841a2965955dd288cfa707a755d05a54e45f8bd476835ec9af4402a2b59a2967",
@@ -576,36 +672,45 @@
120000 => "bd9d26924f05f6daa7f0155f32828ec89e8e29cee9e7121b026a7a3552ac6131",
161500 => "dbe89880474f4bb4f75c227c77ba1cdc024991123b28b8418dbbf7798471ff43",
179620 => "2ad9c65c990ac00426d18e446e0fd7be2ffa69e9a7dcb28358a50b2b78b9f709",
240000 => "7140d1c4b4c2157ca217ee7636f24c9c73db39c4590c4e6eab2e3ea1555088aa",
383640 => "2b6809f094a9215bafc65eb3f110a35127a34be94b7d0590a096c3f126c6f364",
+ 409004 => "487518d663d9f1fa08611d9395ad74d982b667fbdc0e77e9cf39b4f1355908a3",
+ 456000 => "bf34f71cc6366cd487930d06be22f897e34ca6a40501ac7d401be32456372004",
+ 541794 => "1cbccbe6920e7c258bbce1f26211084efb19764aa3224bec3f4320d77d6a2fd2",
}
},
:litecoin_testnet => {
:project => :litecoin,
:magic_head => "\xfc\xc1\xb7\xdc",
:address_version => "6f",
:p2sh_version => "c4",
:privkey_version => "ef",
:default_port => 19333,
- :protocol_version => 60002,
- :min_tx_fee => 2_000_000,
- :min_relay_tx_fee => 1_000_000,
+ :protocol_version => 70002,
+ :min_tx_fee => 100_000, # 0.001 LTC
+ :min_relay_tx_fee => 100_000, # 0.001 LTC
+ :dust => CENT / 10,
+ :per_dust_fee => true,
+ :free_tx_bytes => 5_000,
:coinbase_maturity => 100,
:retarget_interval => 2016,
:retarget_time => 302400, # 3.5 days
:max_money => 84_000_000 * COIN,
:dns_seeds => [
"testnet-seed.litecointools.com",
+ "testnet-seed.ltc.xurious.com",
"testnet-seed.weminemnc.com",
],
:genesis_hash => "f5ae71e26c74beacc88382716aced69cddf3dffff24f384e1808905e0188f68f",
:proof_of_work_limit => 0,
- :alert_pubkeys => [],
+ :alert_pubkeys => ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
:known_nodes => [],
- :checkpoints => {}
+ :checkpoints => {
+ 546 => "a0fea99a6897f531600c8ae53367b126824fd6a847b2b2b73817a95b8e27e602",
+ }
},
:freicoin => {
:project => :freicoin,
@@ -616,10 +721,13 @@
:default_port => 8639,
:protocol_version => 60002,
:max_money => 21_000_000 * COIN,
:min_tx_fee => 50_000,
:min_relay_tx_fee => 10_000,
+ :free_tx_bytes => 1_000,
+ :dust => CENT,
+ :per_dust_fee => false,
:dns_seeds => [ "seed.freico.in", "fledge.freico.in" ],
:genesis_hash => "000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c",
:proof_of_work_limit => 0,
:alert_pubkeys => [],
:known_nodes => [],
@@ -636,20 +744,24 @@
:default_port => 8334,
:protocol_version => 35000,
:max_money => 21_000_000 * COIN,
:min_tx_fee => 50_000,
:min_relay_tx_fee => 10_000,
+ :free_tx_bytes => 1_000,
+ :dust => CENT,
+ :per_dust_fee => true,
:dns_seeds => [],
:genesis_hash => "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770",
:proof_of_work_limit => 0x1d00ffff,
:known_nodes => ["bitcoin.tunl.in", "webbtc.com", "178.32.31.41",
"78.47.86.43", "69.164.206.88", ""],
:checkpoints => {
0 => "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770",
19200 => "d8a7c3e01e1e95bcee015e6fcc7583a2ca60b79e5a3aa0a171eddd344ada903d",
24000 => "425ab0983cf04f43f346a4ca53049d0dc2db952c0a68eb0b55c3bb64108d5371",
97778 => "7553b1e43da01cfcda4335de1caf623e941d43894bd81c2af27b6582f9d83c6f",
+ 165000 => "823d7a54ebab04d14c4ba3508f6b5f25977406f4d389539eac0174d52c6b4b62",
}
},
:namecoin_testnet => {
:project => :namecoin,
@@ -657,9 +769,12 @@
:address_version => "34",
:default_port => 18334,
:protocol_version => 35000,
:min_tx_fee => 50_000,
:min_relay_tx_fee => 10_000,
+ :free_tx_bytes => 1_000,
+ :dust => CENT,
+ :per_dust_fee => true,
:max_money => 21_000_000 * COIN,
:dns_seeds => [],
:genesis_hash => "00000001f8ab0d14bceaeb50d163b0bef15aecf62b87bd5f5c864d37f201db97",
:proof_of_work_limit => 0x1d00ffff,
:known_nodes => ["178.32.31.41"],