Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor for filecoin #22

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
16 changes: 13 additions & 3 deletions datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ const (
Zcash = 133
BitcoinCash = 145
Ethereum = 60
Filecoin = 461

TestnetBitcoin = 1000000
TestnetLitecoin = 1000001
TestnetZcash = 1000133
TestnetBitcoinCash = 1000145
TestnetEthereum = 1000060
TestnetFilecoin = 1000461
)

func (c *CoinType) String() string {
Expand All @@ -44,6 +46,8 @@ func (c *CoinType) String() string {
return "Litecoin"
case Ethereum:
return "Ethereum"
case Filecoin:
return "Filecoin"
case TestnetBitcoin:
return "Testnet Bitcoin"
case TestnetBitcoinCash:
Expand All @@ -54,6 +58,8 @@ func (c *CoinType) String() string {
return "Testnet Litecoin"
case TestnetEthereum:
return "Testnet Ethereum"
case TestnetFilecoin:
return "Testnet Filecoin"
default:
return ""
}
Expand All @@ -71,6 +77,8 @@ func (c *CoinType) CurrencyCode() string {
return "LTC"
case Ethereum:
return "ETH"
case Filecoin:
return "FIL"
case TestnetBitcoin:
return "TBTC"
case TestnetBitcoinCash:
Expand All @@ -81,6 +89,8 @@ func (c *CoinType) CurrencyCode() string {
return "TLTC"
case TestnetEthereum:
return "TETH"
case TestnetFilecoin:
return "TFIL"
default:
return ""
}
Expand Down Expand Up @@ -124,16 +134,16 @@ type Txns interface {
Put(raw []byte, txid, value string, height int, timestamp time.Time, watchOnly bool) error

// Fetch a tx and it's metadata given a hash
Get(txid chainhash.Hash) (Txn, error)
Get(txid string) (Txn, error)

// Fetch all transactions from the db
GetAll(includeWatchOnly bool) ([]Txn, error)

// Update the height of a transaction
UpdateHeight(txid chainhash.Hash, height int, timestamp time.Time) error
UpdateHeight(txid string, height int, timestamp time.Time) error

// Delete a transactions from the db
Delete(txid *chainhash.Hash) error
Delete(txid string) error
}

// Keys provides a database interface for the wallet to save key material, track
Expand Down
148 changes: 73 additions & 75 deletions wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"math/big"
"time"

"github.com/btcsuite/btcd/chaincfg/chainhash"
btc "github.com/btcsuite/btcutil"
hd "github.com/btcsuite/btcutil/hdkeychain"
)
Expand Down Expand Up @@ -46,9 +45,7 @@ import (
// escrowed payment.
type Wallet interface {
walletMustManager
walletMustKeysmither
walletMustBanker
walletCanBumpFee
}

var (
Expand All @@ -68,6 +65,74 @@ type WalletMustManuallyAssociateTransactionToOrder interface {
AssociateTransactionWithOrder(cb TransactionCallback)
}

// EscrowWallet is implemented by wallets capable of performing escrow transactions.
type EscrowWallet interface {
// SweepAddress should sweep all the funds from the provided inputs into the provided `address` using the given
// `key`. If `address` is nil, the funds should be swept into an internal address own by this wallet.
// If the `redeemScript` is not nil, this should be treated as a multisig (p2sh) address and signed accordingly.
//
// This method is called by openbazaar-go in the following scenarios:
// 1) The buyer placed a direct order to a vendor who was offline. The buyer sent funds into a 1 of 2 multisig.
// Upon returning online the vendor accepts the order and calls SweepAddress to move the funds into his wallet.
//
// 2) Same as above but the buyer wishes to cancel the order before the vendor comes online. He calls SweepAddress
// to return the funds from the 1 of 2 multisig back into has wallet.
//
// 3) Same as above but rather than accepting the order, the vendor rejects it. When the buyer receives the reject
// message he calls SweepAddress to move the funds back into his wallet.
//
// 4) The timeout has expired on a 2 of 3 multisig. The vendor calls SweepAddress to claim the funds.
SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (string, error)

// GenerateMultisigScript should deterministically create a redeem script and address from the information provided.
// This method should be strictly limited to taking the input data, combining it to produce the redeem script and
// address and that's it. There is no need to interact with the network or make any transactions when this is called.
//
// Openbazaar-go will call this method in the following situations:
// 1) When the buyer places an order he passes in the relevant keys for each party to get back the address where
// the funds should be sent and the redeem script. The redeem script is saved in order (and openbazaar-go database).
//
// 2) The vendor calls this method when he receives and order so as to validate that the address they buyer is sending
// funds to is indeed correctly constructed. If this method fails to return the same values for the vendor as it
// did the buyer, the vendor will reject the order.
//
// 3) The moderator calls this function upon receiving a dispute so that he can validate the payment address for the
// order and make sure neither party is trying to maliciously lie about the details of the dispute to get the moderator
// to release the funds.
//
// Note that according to the order flow, this method is called by the buyer *before* the order is sent to the vendor,
// and before the vendor validates the order. Only after the buyer hears back from the vendor does the buyer send
// funds (either from an external wallet or via the `Spend` method) to the address specified in this method's return.
//
// `threshold` is the number of keys required to release the funds from the address. If `threshold` is two and len(keys)
// is three, this is a two of three multisig. If `timeoutKey` is not nil, then the script should allow the funds to
// be released with a signature from the `timeoutKey` after the `timeout` duration has passed.
// For example:
// OP_IF 2 <buyerPubkey> <vendorPubkey> <moderatorPubkey> 3 OP_ELSE <timeout> OP_CHECKSEQUENCEVERIFY <timeoutKey> OP_CHECKSIG OP_ENDIF
//
// If `timeoutKey` is nil then the a normal multisig without a timeout should be created.
GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btc.Address, redeemScript []byte, err error)

// CreateMultisigSignature should build a transaction using the given inputs and outputs and sign it with the
// provided key. A list of signatures (one for each input) should be returned.
//
// This method is called by openbazaar-go by each party whenever they decide to release the funds from escrow.
// This method should not actually move any funds or make any transactions, only create necessary signatures to
// do so. The caller will then take the signature and share it with the other parties. Once all parties have shared
// their signatures, the person who wants to release the funds collects them and uses them as an input to the
// `Multisign` method.
CreateMultisigSignature(ins []TransactionInput, outs []TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]Signature, error)

// Multisign collects all of the signatures generated by the `CreateMultisigSignature` function and builds a final
// transaction that can then be broadcast to the blockchain. The []byte return is the raw transaction. It should be
// broadcasted if `broadcast` is true. If the signatures combine and produce an invalid transaction then an error
// should be returned.
//
// This method is called by openbazaar-go by whichever party to the escrow is trying to release the funds only after
// all needed parties have signed using `CreateMultisigSignature` and have shared their signatures with each other.
Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error)
}

type walletMustManager interface {
// Start is called when the openbazaar-go daemon starts up. At this point in time
// the wallet implementation should start syncing and/or updating balances, but
Expand Down Expand Up @@ -140,21 +205,19 @@ type walletMustManager interface {
Transactions() ([]Txn, error)

// GetTransaction return info on a specific transaction given the txid.
GetTransaction(txid chainhash.Hash) (Txn, error)
GetTransaction(txid string) (Txn, error)

// ChainTip returns the best block hash and height of the blockchain.
ChainTip() (uint32, chainhash.Hash)
ChainTip() (uint32, string)

// ReSyncBlockchain is called in response to a user action to rescan transactions. API based
// wallets should do another scan of their addresses to find anything missing. Full node, or SPV
// wallets should rescan/re-download blocks starting at the fromTime.
ReSyncBlockchain(fromTime time.Time)

// GetConfirmations returns the number of confirmations and the height for a transaction.
GetConfirmations(txid chainhash.Hash) (confirms, atHeight uint32, err error)
}
GetConfirmations(txid string) (confirms, atHeight uint32, err error)

type walletMustKeysmither interface {
// ChildKey generate a child key using the given chaincode. Each openbazaar-go node
// keeps a master key (an hd secp256k1 key) that it uses in multisig transactions.
// Rather than use the key directly (which would result in an on chain privacy leak),
Expand All @@ -170,54 +233,6 @@ type walletMustKeysmither interface {
// transaction that the other party(s) signed does indeed pay to an address that we
// control.
HasKey(addr btc.Address) bool

// GenerateMultisigScript should deterministically create a redeem script and address from the information provided.
// This method should be strictly limited to taking the input data, combining it to produce the redeem script and
// address and that's it. There is no need to interact with the network or make any transactions when this is called.
//
// Openbazaar-go will call this method in the following situations:
// 1) When the buyer places an order he passes in the relevant keys for each party to get back the address where
// the funds should be sent and the redeem script. The redeem script is saved in order (and openbazaar-go database).
//
// 2) The vendor calls this method when he receives and order so as to validate that the address they buyer is sending
// funds to is indeed correctly constructed. If this method fails to return the same values for the vendor as it
// did the buyer, the vendor will reject the order.
//
// 3) The moderator calls this function upon receiving a dispute so that he can validate the payment address for the
// order and make sure neither party is trying to maliciously lie about the details of the dispute to get the moderator
// to release the funds.
//
// Note that according to the order flow, this method is called by the buyer *before* the order is sent to the vendor,
// and before the vendor validates the order. Only after the buyer hears back from the vendor does the buyer send
// funds (either from an external wallet or via the `Spend` method) to the address specified in this method's return.
//
// `threshold` is the number of keys required to release the funds from the address. If `threshold` is two and len(keys)
// is three, this is a two of three multisig. If `timeoutKey` is not nil, then the script should allow the funds to
// be released with a signature from the `timeoutKey` after the `timeout` duration has passed.
// For example:
// OP_IF 2 <buyerPubkey> <vendorPubkey> <moderatorPubkey> 3 OP_ELSE <timeout> OP_CHECKSEQUENCEVERIFY <timeoutKey> OP_CHECKSIG OP_ENDIF
//
// If `timeoutKey` is nil then the a normal multisig without a timeout should be created.
GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btc.Address, redeemScript []byte, err error)

// CreateMultisigSignature should build a transaction using the given inputs and outputs and sign it with the
// provided key. A list of signatures (one for each input) should be returned.
//
// This method is called by openbazaar-go by each party whenever they decide to release the funds from escrow.
// This method should not actually move any funds or make any transactions, only create necessary signatures to
// do so. The caller will then take the signature and share it with the other parties. Once all parties have shared
// their signatures, the person who wants to release the funds collects them and uses them as an input to the
// `Multisign` method.
CreateMultisigSignature(ins []TransactionInput, outs []TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]Signature, error)

// Multisign collects all of the signatures generated by the `CreateMultisigSignature` function and builds a final
// transaction that can then be broadcast to the blockchain. The []byte return is the raw transaction. It should be
// broadcasted if `broadcast` is true. If the signatures combine and produce an invalid transaction then an error
// should be returned.
//
// This method is called by openbazaar-go by whichever party to the escrow is trying to release the funds only after
// all needed parties have signed using `CreateMultisigSignature` and have shared their signatures with each other.
Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error)
}

type walletMustBanker interface {
Expand All @@ -238,7 +253,7 @@ type walletMustBanker interface {
// be swept to the provided payment address. For most coins this entails subtracting the
// transaction fee from the total amount being sent rather than adding it on as is normally
// the case when spendAll is false.
Spend(amount big.Int, addr btc.Address, feeLevel FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error)
Spend(amount big.Int, addr btc.Address, feeLevel FeeLevel, referenceID string, spendAll bool) (string, error)

// EstimateFee should return the estimate fee that will be required to make a transaction
// spending from the given inputs to the given outputs. FeePerByte is denominated in
Expand All @@ -253,31 +268,14 @@ type walletMustBanker interface {
//
// All amounts should be in the coin's base unit (for example: satoshis).
EstimateSpendFee(amount big.Int, feeLevel FeeLevel) (big.Int, error)

// SweepAddress should sweep all the funds from the provided inputs into the provided `address` using the given
// `key`. If `address` is nil, the funds should be swept into an internal address own by this wallet.
// If the `redeemScript` is not nil, this should be treated as a multisig (p2sh) address and signed accordingly.
//
// This method is called by openbazaar-go in the following scenarios:
// 1) The buyer placed a direct order to a vendor who was offline. The buyer sent funds into a 1 of 2 multisig.
// Upon returning online the vendor accepts the order and calls SweepAddress to move the funds into his wallet.
//
// 2) Same as above but the buyer wishes to cancel the order before the vendor comes online. He calls SweepAddress
// to return the funds from the 1 of 2 multisig back into has wallet.
//
// 3) Same as above but rather than accepting the order, the vendor rejects it. When the buyer receives the reject
// message he calls SweepAddress to move the funds back into his wallet.
//
// 4) The timeout has expired on a 2 of 3 multisig. The vendor calls SweepAddress to claim the funds.
SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (*chainhash.Hash, error)
}

type walletCanBumpFee interface {
// BumpFee should attempt to bump the fee on a given unconfirmed transaction (if possible) to
// try to get it confirmed and return the txid of the new transaction (if one exists).
// Since this method is only called in response to user action, it is acceptable to
// return an error if this functionality is not available in this wallet or on the network.
BumpFee(txid chainhash.Hash) (*chainhash.Hash, error)
BumpFee(txid string) (string, error)
}

type FeeLevel int
Expand Down