decred.org/dcrdex@v1.0.5/server/asset/common.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package asset 5 6 import ( 7 "context" 8 "fmt" 9 "time" 10 11 "decred.org/dcrdex/dex" 12 ) 13 14 // BackendInfo provides auxiliary information about a backend. 15 type BackendInfo struct { 16 SupportsDynamicTxFee bool 17 } 18 19 // CoinNotFoundError is to be returned from Contract, Redemption, and 20 // FundingCoin when the specified transaction cannot be found. Used by the 21 // server to handle network latency. 22 const ( 23 CoinNotFoundError = dex.ErrorKind("coin not found") 24 ErrRequestTimeout = dex.ErrorKind("request timeout") 25 ) 26 27 // Backend is a blockchain backend. TODO: Plumb every method with a cancellable 28 // request with a Context, which will prevent backend shutdown from cancelling 29 // requests, but is more idiomatic these days. 30 type Backend interface { 31 // It is expected that Connect from dex.Connector is called and returns 32 // before use of the asset, and that it is only called once for the life 33 // of the asset. 34 dex.Connector 35 // Contract returns a Contract only for outputs that would be spendable on 36 // the blockchain immediately. Contract data (e.g. the redeem script for 37 // UTXO assets) is required in order to calculate sigScript length and 38 // verify pubkeys. 39 Contract(coinID []byte, contractData []byte) (*Contract, error) 40 // TxData fetches the raw transaction data for the specified coin. 41 TxData(coinID []byte) ([]byte, error) 42 // ValidateSecret checks that the secret satisfies the contract. 43 ValidateSecret(secret, contractData []byte) bool 44 // Redemption returns a Coin for redemptionID, a transaction input, that 45 // spends contract ID, an output containing the swap contract. 46 Redemption(redemptionID, contractID, contractData []byte) (Coin, error) 47 // BlockChannel creates and returns a new channel on which to receive updates 48 // when new blocks are connected. 49 BlockChannel(size int) <-chan *BlockUpdate 50 // CheckSwapAddress checks that the given address is parseable, and suitable 51 // as a redeem address in a swap contract script or initiation. 52 CheckSwapAddress(string) bool 53 // ValidateCoinID checks the coinID to ensure it can be decoded, returning a 54 // human-readable string if it is valid. 55 // Note: ValidateCoinID is NOT used for funding coin IDs for account-based 56 // assets. This rule is only enforced by code patterns right now, but we may 57 // consider adding separate methods in the future. 58 ValidateCoinID(coinID []byte) (string, error) 59 // ValidateContract ensures that the swap contract is constructed properly 60 // for the asset. 61 ValidateContract(contract []byte) error 62 // FeeRate returns the current optimal fee rate in atoms / byte. 63 FeeRate(context.Context) (uint64, error) 64 // Synced should return true when the blockchain is synced and ready for 65 // fee rate estimation. 66 Synced() (bool, error) 67 // Info provides auxiliary information about a backend. 68 Info() *BackendInfo 69 // ValidateFeeRate checks that the transaction fees used to initiate the 70 // contract are sufficient. 71 ValidateFeeRate(coin Coin, reqFeeRate uint64) bool 72 } 73 74 // OutputTracker is implemented by backends for UTXO-based blockchains. 75 // OutputTracker tracks the value and spend-status of transaction outputs. 76 type OutputTracker interface { 77 // VerifyUnspentCoin attempts to verify a coin ID by decoding the coin ID 78 // and retrieving the corresponding Coin. If the coin is not found or no 79 // longer unspent, an asset.CoinNotFoundError is returned. Use FundingCoin 80 // for more UTXO data. 81 VerifyUnspentCoin(ctx context.Context, coinID []byte) error 82 // FundingCoin returns the unspent coin at the specified location. Coins 83 // with non-standard pkScripts or scripts that require zero signatures to 84 // redeem must return an error. 85 FundingCoin(ctx context.Context, coinID []byte, redeemScript []byte) (FundingCoin, error) 86 // ValidateOrderFunding validates that the supplied utxos are enough to fund an order. 87 ValidateOrderFunding(swapVal, valSum, inputCount, inputsSize, maxSwaps uint64, nfo *dex.Asset) bool 88 } 89 90 // AccountBalancer is implemented by backends for account-based blockchains. 91 // An AccountBalancer reports the current balance for an account. 92 type AccountBalancer interface { 93 // AccountBalance retrieves the current account balance. 94 AccountBalance(addr string) (uint64, error) 95 // ValidateSignature checks that the pubkey is correct for the address and 96 // that the signature shows ownership of the associated private key. 97 // IMPORTANT: As part of signature validation, the asset backend should 98 // validate the address against a STRICT standard. Case, prefixes, suffixes, 99 // etc. must be exactly the same order-to-order, since the address string 100 // is used as a key for various accounting operations throughout DEX. 101 ValidateSignature(addr string, pubkey, msg, sig []byte) error 102 // RedeemSize is the gas used for a single redemption. 103 RedeemSize() uint64 104 InitTxSize() uint64 105 } 106 107 // TokenBacker is implemented by Backends that support degenerate tokens. 108 type TokenBacker interface { 109 TokenBackend(assetID uint32, configPath string) (Backend, error) 110 } 111 112 // Coin represents a transaction input or output. 113 type Coin interface { 114 // Confirmations returns the number of confirmations for a Coin's 115 // transaction. Because a Coin can become invalid after once being 116 // considered valid, this condition should be checked for during 117 // confirmation counting and an error returned if this Coin is no longer 118 // ready to spend. An unmined transaction should have zero confirmations. A 119 // transaction in the current best block should have one confirmation. A 120 // negative number can be returned if error is not nil. 121 Confirmations(context.Context) (int64, error) 122 // ID is the coin ID. 123 ID() []byte 124 // TxID is a transaction identifier for the coin. 125 TxID() string 126 // String is a human readable representation of the Coin. 127 String() string 128 // Value is the coin value. 129 Value() uint64 130 // FeeRate returns the transaction fee rate, in atoms/byte equivalent. 131 FeeRate() uint64 132 } 133 134 // FundingCoin is some unspent value on the blockchain. 135 type FundingCoin interface { 136 Coin() Coin 137 // Auth checks that the owner of the provided pubkeys can spend the 138 // FundingCoin. The signatures (sigs) generated with the private keys 139 // corresponding to pubkeys must validate against the pubkeys and signing 140 // message (msg). 141 Auth(pubkeys, sigs [][]byte, msg []byte) error 142 // SpendSize returns the size of the serialized input that spends this 143 // FundingCoin. 144 SpendSize() uint32 145 } 146 147 // Contract is an atomic swap contract. 148 type Contract struct { 149 Coin 150 // SwapAddress is the receiving address of the swap contract. 151 SwapAddress string 152 // ContractData is essential data about this swap. For example, the redeem 153 // script for UTXO contracts, or a secret hash that keys swaps for account- 154 // based contracts. 155 ContractData []byte 156 // SecretHash is the secret key hash used for this swap. This should be used 157 // to validate a counterparty contract on another chain. 158 SecretHash []byte 159 // LockTime is the refund locktime. 160 LockTime time.Time 161 // TxData is raw transaction data. This data is provided for some assets 162 // to aid in SPV compatibility. 163 TxData []byte 164 } 165 166 // BlockUpdate is sent over the update channel when a tip change is detected. 167 type BlockUpdate struct { 168 Err error 169 Reorg bool // TODO: Not used. Remove and update through btc and dcr. Don't really need the BlockUpdate struct at all. 170 } 171 172 // ConnectionError error should be sent over the block update channel if a 173 // connection error is detected by the Backend. 174 type ConnectionError error 175 176 // NewConnectionError is a constructor for a ConnectionError. 177 func NewConnectionError(s string, a ...any) ConnectionError { 178 return ConnectionError(fmt.Errorf(s, a...)) 179 } 180 181 // BackedAsset is a dex.Asset with a Backend. 182 type BackedAsset struct { 183 dex.Asset 184 Backend Backend 185 }