Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 16 additions & 53 deletions src/address.js
Original file line number Diff line number Diff line change
@@ -1,64 +1,27 @@
var base58 = require('./base58')
var assert = require('assert')
var base58check = require('./base58check')
var convert = require('./convert')
var bitcoin = require('./network').bitcoin.pubKeyHash

function Address(bytes, version) {
if (!(this instanceof Address)) {
return new Address(bytes, version)
}
function Address(hash, version) {
assert(Buffer.isBuffer(hash), 'First argument must be a Buffer')
assert.strictEqual(hash.length, 20, 'Invalid hash length')
assert.strictEqual(version & 0xFF, version, 'Invalid version byte')

if (bytes instanceof Address) {
this.hash = bytes.hash
this.version = bytes.version
}
else if (typeof bytes === 'string') {
if (bytes.length <= 35) {
var decode = base58check.decode(bytes)

this.hash = decode.payload
this.version = decode.version
}
else if (bytes.length <= 40) {
this.hash = convert.hexToBytes(bytes)
this.version = version || bitcoin
}
else {
throw new Error('Invalid or unrecognized input')
}
}
else {
this.hash = bytes
this.version = version || bitcoin
}
this.hash = hash
this.version = version
}

/**
* Serialize this object as a standard Bitcoin address.
* Returns the address as a base58-encoded string in the standardized format.
*/
Address.prototype.toString = function () {
return base58check.encode(this.hash.slice(0), this.version)
}
// Import functions
Address.fromBase58Check = function(string) {
var decode = base58check.decode(string)

/**
* Returns the version of an address, e.g. if the address belongs to the main
* net or the test net.
*/
Address.getVersion = function (address) {
return base58.decode(address)[0]
return new Address(decode.payload, decode.version)
}
Address.prototype.fromString = Address.prototype.fromBase58Check

/**
* Returns true if a bitcoin address is a valid address, otherwise false.
*/
Address.validate = function (address) {
try {
base58check.decode(address)
return true
} catch (e) {
return false
}
// Export functions
Address.prototype.toBase58Check = function () {
return base58check.encode(this.hash, this.version)
}
Address.prototype.toString = Address.prototype.toBase58Check

module.exports = Address
2 changes: 2 additions & 0 deletions src/eckey.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ ECPubKey.prototype.verify = function(hash, sig) {
}

ECPubKey.prototype.getAddress = function(version) {
version = version || network.bitcoin.pubKeyHash

return new Address(crypto.hash160(this.toBuffer()), version)
}

Expand Down
6 changes: 5 additions & 1 deletion src/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@ function sign(key, message) {
return sig
}

// FIXME: stricter API?
function verify(address, sig, message) {
if (typeof address === 'string') {
address = Address.fromBase58Check(address)
}

sig = ecdsa.parseSigCompact(sig)

var pubKey = new ECPubKey(ecdsa.recoverPubKey(sig.r, sig.s, magicHash(message), sig.i))
pubKey.compressed = !!(sig.i & 4)

address = new Address(address)
return pubKey.getAddress(address.version).toString() === address.toString()
}

Expand Down
54 changes: 30 additions & 24 deletions src/script.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
var assert = require('assert')
var Address = require('./address')
var crypto = require('./crypto')
var convert = require('./convert')
var network = require('./network')
var Network = require('./network')
var Opcode = require('./opcode')

function Script(data) {
Expand Down Expand Up @@ -211,22 +212,22 @@ Script.prototype.toScriptHash = function() {
return crypto.hash160(this.buffer)
}

//TODO: support testnet
Script.prototype.getToAddress = function() {
Script.prototype.getToAddress = function(network) {
network = network || Network.bitcoin

if(isPubkeyhash.call(this)) {
return new Address(this.chunks[2])
return new Address(new Buffer(this.chunks[2]), network.pubKeyHash)
}

if(isScripthash.call(this)) {
return new Address(this.chunks[1], 5)
}
assert(isScripthash.call(this))

return new Address(this.chunks[1], 5)
return new Address(new Buffer(this.chunks[1]), network.scriptHash)
}

//TODO: support testnet
Script.prototype.getFromAddress = function(){
return new Address(this.simpleInHash())
Script.prototype.getFromAddress = function(version) {
version = version || Network.bitcoin.pubKeyHash

return new Address(this.simpleInHash(), version)
}

/**
Expand Down Expand Up @@ -364,25 +365,30 @@ Script.prototype.writeBytes = function(data) {
/**
* Create an output for an address
*/
Script.createOutputScript = function(address) {
Script.createOutputScript = function(address, network) {
assert(address instanceof Address)
network = network || Network.bitcoin

var script = new Script()

address = new Address(address)
if (address.version == network.bitcoin.scriptHash ||
address.version == network.testnet.scriptHash) {
// Standard pay-to-script-hash
// Standard pay-to-script-hash
if (address.version === network.scriptHash) {
script.writeOp(Opcode.map.OP_HASH160)
script.writeBytes(address.hash)
script.writeOp(Opcode.map.OP_EQUAL)

return script
}
else {
// Standard pay-to-pubkey-hash
script.writeOp(Opcode.map.OP_DUP)
script.writeOp(Opcode.map.OP_HASH160)
script.writeBytes(address.hash)
script.writeOp(Opcode.map.OP_EQUALVERIFY)
script.writeOp(Opcode.map.OP_CHECKSIG)
}

assert.strictEqual(address.version, network.pubKeyHash, 'Unknown address type')

// Standard pay-to-pubkey-hash
script.writeOp(Opcode.map.OP_DUP)
script.writeOp(Opcode.map.OP_HASH160)
script.writeBytes(address.hash)
script.writeOp(Opcode.map.OP_EQUALVERIFY)
script.writeOp(Opcode.map.OP_CHECKSIG)

return script
}

Expand Down
27 changes: 20 additions & 7 deletions src/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var convert = require('./convert')
var crypto = require('./crypto')
var ECKey = require('./eckey').ECKey
var ecdsa = require('./ecdsa')
var Network = require('./network')

var Transaction = function (doc) {
if (!(this instanceof Transaction)) { return new Transaction(doc) }
Expand Down Expand Up @@ -84,23 +85,33 @@ Transaction.prototype.addInput = function (tx, outIndex) {
* i) An existing TransactionOut object
* ii) An address object or an address and a value
* iii) An address:value string
* iv) Either ii), iii) with an optional network argument
*
* FIXME: This is a bit convoluted
*/
Transaction.prototype.addOutput = function (address, value) {
Transaction.prototype.addOutput = function (address, value, network) {
if (arguments[0] instanceof TransactionOut) {
this.outs.push(arguments[0])
return
}

if (arguments[0].indexOf(':') >= 0) {
network = value

var args = arguments[0].split(':')
address = args[0]
value = parseInt(args[1])
}

network = network || Network.bitcoin

if (typeof address === 'string') {
address = Address.fromBase58Check(address)
}

this.outs.push(new TransactionOut({
value: value,
script: Script.createOutputScript(address)
script: Script.createOutputScript(address, network)
}))
}

Expand Down Expand Up @@ -297,18 +308,19 @@ Transaction.deserialize = function(buffer) {

/**
* Signs a standard output at some index with the given key
* FIXME: network support is ugly
*/
Transaction.prototype.sign = function(index, key, type) {
Transaction.prototype.sign = function(index, key, type, network) {
assert(key instanceof ECKey)
type = type || SIGHASH_ALL
network = network || Network.bitcoin

var pub = key.pub.toBuffer()
var hash160 = crypto.hash160(pub)
var script = Script.createOutputScript(new Address(hash160))
var address = key.pub.getAddress(network.pubKeyHash)
var script = Script.createOutputScript(address, network)
var hash = this.hashTransactionForSignature(script, index, type)
var sig = key.sign(hash).concat([type])

this.ins[index].script = Script.createInputScript(sig, pub)
this.ins[index].script = Script.createInputScript(sig, key.pub)
}

// Takes outputs of the form [{ output: 'txhash:index', address: 'address' },...]
Expand Down Expand Up @@ -413,6 +425,7 @@ TransactionIn.prototype.clone = function () {
})
}

// FIXME: Support for alternate networks
var TransactionOut = function (data) {
this.script =
data.script instanceof Script ? data.script.clone()
Expand Down
Loading