2015-12-26 21:35:15 +03:00
|
|
|
package channeldb
|
2015-12-24 21:41:15 +03:00
|
|
|
|
|
|
|
import (
|
2015-12-26 03:00:44 +03:00
|
|
|
"bytes"
|
2017-05-05 01:19:21 +03:00
|
|
|
"encoding/binary"
|
2016-09-03 04:51:34 +03:00
|
|
|
"fmt"
|
2016-06-21 07:39:50 +03:00
|
|
|
"io"
|
2016-10-27 00:47:02 +03:00
|
|
|
"net"
|
2016-03-24 08:39:52 +03:00
|
|
|
"sync"
|
2015-12-24 21:41:15 +03:00
|
|
|
|
2016-03-23 04:46:30 +03:00
|
|
|
"github.com/boltdb/bolt"
|
2017-06-16 23:28:26 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2016-12-14 17:01:48 +03:00
|
|
|
"github.com/lightningnetwork/lnd/shachain"
|
2016-05-15 17:17:44 +03:00
|
|
|
"github.com/roasbeef/btcd/btcec"
|
2017-05-05 01:19:21 +03:00
|
|
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
2016-05-15 17:17:44 +03:00
|
|
|
"github.com/roasbeef/btcd/wire"
|
|
|
|
"github.com/roasbeef/btcutil"
|
2015-12-24 21:41:15 +03:00
|
|
|
)
|
2015-12-26 02:00:20 +03:00
|
|
|
|
|
|
|
var (
|
2016-03-24 08:39:52 +03:00
|
|
|
// openChanBucket stores all the currently open channels. This bucket
|
|
|
|
// has a second, nested bucket which is keyed by a node's ID. Additionally,
|
|
|
|
// at the base level of this bucket several prefixed keys are stored which
|
2017-01-13 08:01:50 +03:00
|
|
|
// house channel metadata such as total satoshis sent, number of updates
|
2016-03-24 08:39:52 +03:00
|
|
|
// etc. These fields are stored at this top level rather than within a
|
2016-11-22 23:50:27 +03:00
|
|
|
// node's channel bucket in order to facilitate sequential prefix scans
|
2016-03-24 08:39:52 +03:00
|
|
|
// to gather stats such as total satoshis received.
|
|
|
|
openChannelBucket = []byte("ocb")
|
|
|
|
|
2016-11-22 23:50:27 +03:00
|
|
|
// chanIDBucket is a third-level bucket stored within a node's ID bucket
|
2016-06-21 07:39:50 +03:00
|
|
|
// in the open channel bucket. The resolution path looks something like:
|
|
|
|
// ocb -> nodeID -> cib. This bucket contains a series of keys with no
|
|
|
|
// values, these keys are the channel ID's of all the active channels
|
|
|
|
// we currently have with a specified nodeID. This bucket acts as an
|
|
|
|
// additional indexing allowing random access and sequential scans over
|
|
|
|
// active channels.
|
|
|
|
chanIDBucket = []byte("cib")
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
// closedChannelBucket stores summarization information concerning
|
|
|
|
// previously open, but now closed channels.
|
|
|
|
closedChannelBucket = []byte("ccb")
|
|
|
|
|
|
|
|
// channelLogBucket is dedicated for storing the necessary delta state
|
|
|
|
// between channel updates required to re-construct a past state in
|
2017-01-13 08:01:50 +03:00
|
|
|
// order to punish a counterparty attempting a non-cooperative channel
|
2016-10-26 02:11:23 +03:00
|
|
|
// closure. A channel log bucket is created for each node and is nested
|
|
|
|
// within a node's ID bucket.
|
2016-03-24 08:39:52 +03:00
|
|
|
channelLogBucket = []byte("clb")
|
|
|
|
|
2016-10-26 02:11:23 +03:00
|
|
|
// identityKey is the key for storing this node's current LD identity
|
|
|
|
// key.
|
2016-03-24 08:39:52 +03:00
|
|
|
identityKey = []byte("idk")
|
|
|
|
|
|
|
|
// The following prefixes are stored at the base level within the
|
|
|
|
// openChannelBucket. In order to retrieve a particular field for an
|
|
|
|
// active, or historic channel, append the channels ID to the prefix:
|
|
|
|
// key = prefix || chanID. Storing certain fields at the top level
|
|
|
|
// using a prefix scheme serves two purposes: first to facilitate
|
|
|
|
// sequential prefix scans, and second to eliminate write amplification
|
|
|
|
// caused by serializing/deserializing the *entire* struct with each
|
|
|
|
// update.
|
2017-07-29 20:58:39 +03:00
|
|
|
chanCapacityPrefix = []byte("ccp")
|
|
|
|
selfBalancePrefix = []byte("sbp")
|
|
|
|
theirBalancePrefix = []byte("tbp")
|
|
|
|
minFeePerKwPrefix = []byte("mfp")
|
|
|
|
chanConfigPrefix = []byte("chan-config")
|
|
|
|
updatePrefix = []byte("uup")
|
|
|
|
satSentPrefix = []byte("ssp")
|
|
|
|
satReceivedPrefix = []byte("srp")
|
|
|
|
commitFeePrefix = []byte("cfp")
|
|
|
|
isPendingPrefix = []byte("pdg")
|
|
|
|
confInfoPrefix = []byte("conf-info")
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
// chanIDKey stores the node, and channelID for an active channel.
|
|
|
|
chanIDKey = []byte("cik")
|
|
|
|
|
|
|
|
// commitKeys stores both commitment keys (ours, and theirs) for an
|
|
|
|
// active channel. Our private key is stored in an encrypted format
|
|
|
|
// using channeldb's currently registered cryptoSystem.
|
|
|
|
commitKeys = []byte("ckk")
|
|
|
|
|
|
|
|
// commitTxnsKey stores the full version of both current, non-revoked
|
|
|
|
// commitment transactions in addition to the csvDelay for both.
|
|
|
|
commitTxnsKey = []byte("ctk")
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// currentHtlcKey stores the set of fully locked-in HTLCs on our latest
|
|
|
|
// commitment state.
|
2016-09-07 05:17:34 +03:00
|
|
|
currentHtlcKey = []byte("chk")
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// fundingTxnKey stores the funding output, the multi-sig keys used in
|
|
|
|
// the funding output, and further information detailing if the
|
|
|
|
// transaction is "open", or not and how many confirmations required
|
|
|
|
// until it's considered open.
|
2016-03-24 08:39:52 +03:00
|
|
|
fundingTxnKey = []byte("fsk")
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// revocationStateKey stores their current revocation hash, our
|
2016-12-14 17:01:48 +03:00
|
|
|
// preimage producer and their preimage store.
|
2017-07-29 20:58:39 +03:00
|
|
|
revocationStateKey = []byte("esk")
|
2015-12-26 02:00:20 +03:00
|
|
|
)
|
|
|
|
|
2016-11-16 04:41:22 +03:00
|
|
|
// ChannelType is an enum-like type that describes one of several possible
|
|
|
|
// channel types. Each open channel is associated with a particular type as the
|
|
|
|
// channel type may determine how higher level operations are conducted such as
|
2017-01-13 08:01:50 +03:00
|
|
|
// fee negotiation, channel closing, the format of HTLCs, etc.
|
2016-11-16 04:41:22 +03:00
|
|
|
// TODO(roasbeef): split up per-chain?
|
|
|
|
type ChannelType uint8
|
|
|
|
|
|
|
|
const (
|
2016-11-16 22:45:10 +03:00
|
|
|
// NOTE: iota isn't used here for this enum needs to be stable
|
|
|
|
// long-term as it will be persisted to the database.
|
|
|
|
|
2016-11-16 04:41:22 +03:00
|
|
|
// SingleFunder represents a channel wherein one party solely funds the
|
|
|
|
// entire capacity of the channel.
|
2016-11-16 22:45:10 +03:00
|
|
|
SingleFunder = 0
|
2016-11-16 04:41:22 +03:00
|
|
|
|
|
|
|
// DualFunder represents a channel wherein both parties contribute
|
|
|
|
// funds towards the total capacity of the channel. The channel may be
|
|
|
|
// funded symmetrically or asymmetrically.
|
2016-11-16 22:45:10 +03:00
|
|
|
DualFunder = 1
|
2016-11-16 04:41:22 +03:00
|
|
|
)
|
|
|
|
|
2017-07-29 05:09:49 +03:00
|
|
|
// ChannelConstraints represents a set of constraints meant to allow a node to
|
|
|
|
// limit their exposure, enact flow control and ensure that all HTLC's are
|
|
|
|
// economically relevant This struct will be mirrored for both sides of the
|
|
|
|
// channel, as each side will enforce various constraints that MUST be adhered
|
|
|
|
// to for the life time of the channel. The parameters for each of these
|
|
|
|
// constraints is static for the duration of the channel, meaning the channel
|
|
|
|
// must be teared down for them to change.
|
|
|
|
type ChannelConstraints struct {
|
|
|
|
// DustLimit is the min satoshis/kilo-weight that should be paid within
|
|
|
|
// the commitment transaction for the entire duration of the channel's
|
|
|
|
// lifetime. This field may be updated during normal operation of the
|
|
|
|
// channel as on-chain conditions change.
|
|
|
|
DustLimit btcutil.Amount
|
|
|
|
|
|
|
|
// MaxPendingAmount is the maximum pending HTLC value that can be
|
|
|
|
// present within the channel at a particular time. This value is set
|
|
|
|
// by the initiator of the channel and must be upheld at all times.
|
|
|
|
//
|
|
|
|
// TODO(roasbeef): in mSAT
|
|
|
|
MaxPendingAmount btcutil.Amount
|
|
|
|
|
|
|
|
// ChanReserve is an absolute reservation on the channel for this
|
|
|
|
// particular node. This means that the current settled balance for
|
|
|
|
// this node CANNOT dip below the reservation amount. This acts as a
|
|
|
|
// defense against costless attacks when either side no longer has any
|
|
|
|
// skin in the game.
|
|
|
|
//
|
|
|
|
// TODO(roasbeef): need to swap above, i tell them what reserve, then
|
|
|
|
// other way around
|
|
|
|
ChanReserve btcutil.Amount
|
|
|
|
|
|
|
|
// MinHTLC is the minimum HTLC accepted for a direction of the channel.
|
|
|
|
// If any HTLC's below this amount are offered, then the HTLC will be
|
|
|
|
// rejected. This, in tandem with the dust limit allows a node to
|
|
|
|
// regulate the smallest HTLC that it deems economically relevant.
|
|
|
|
//
|
|
|
|
// TODO(roasbeef): in mSAT
|
|
|
|
MinHTLC btcutil.Amount
|
|
|
|
|
|
|
|
// MaxAcceptedHtlcs is the maximum amount of HTLC's that are to be
|
|
|
|
// accepted by the owner of this set of constraints. This allows each
|
|
|
|
// node to limit their over all exposure to HTLC's that may need to be
|
|
|
|
// acted upon in the case of a unilateral channel closure or a contract
|
|
|
|
// breach.
|
|
|
|
MaxAcceptedHtlcs uint16
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChannelConfig is a struct that houses the various configuration opens for
|
|
|
|
// channels. Each side maintains an instance of this configuration file as it
|
|
|
|
// governs: how the funding and commitment transaction to be created, the
|
|
|
|
// nature of HTLC's allotted, the keys to be used for delivery, and relative
|
|
|
|
// time lock parameters.
|
|
|
|
type ChannelConfig struct {
|
|
|
|
// ChannelConstraints is the set of constraints that must be upheld for
|
|
|
|
// the duration of the channel for ths owner of this channel
|
|
|
|
// configuration. Constraints govern a number of flow control related
|
|
|
|
// parameters, also including the smallest HTLC that will be accepted
|
|
|
|
// by a participant.
|
|
|
|
ChannelConstraints
|
|
|
|
|
|
|
|
// CsvDelay is the relative time lock delay expressed in blocks. Any
|
|
|
|
// settled outputs that pay to the owner of this channel configuration
|
|
|
|
// MUST ensure that the delay branch uses this value as the relative
|
|
|
|
// time lock. Similarly, any HTLC's offered by this node should use
|
|
|
|
// this value as well.
|
|
|
|
CsvDelay uint16
|
|
|
|
|
|
|
|
// MultiSigKey is the key to be used within the 2-of-2 output script
|
|
|
|
// for the owner of this channel config.
|
|
|
|
MultiSigKey *btcec.PublicKey
|
|
|
|
|
|
|
|
// RevocationBasePoint is the base public key to be used when deriving
|
|
|
|
// revocation keys for the remote node's commitment transaction. This
|
|
|
|
// will be combined along with a per commitment secret to derive a
|
|
|
|
// unique revocation key for each state.
|
|
|
|
RevocationBasePoint *btcec.PublicKey
|
|
|
|
|
|
|
|
// PaymentBasePoint is the based public key to be used when deriving
|
|
|
|
// the key used within the non-delayed pay-to-self output on the
|
|
|
|
// commitment transaction for a node. This will be combined with a
|
|
|
|
// tweak derived from the per-commitment point to ensure unique keys
|
|
|
|
// for each commitment transaction.
|
|
|
|
PaymentBasePoint *btcec.PublicKey
|
|
|
|
|
|
|
|
// DelayBasePoint is the based public key to be used when deriving the
|
|
|
|
// key used within the delayed pay-to-self output on the commitment
|
|
|
|
// transaction for a node. This will be combined with a tweak derived
|
|
|
|
// from the per-commitment point to ensure unique keys for each
|
|
|
|
// commitment transaction.
|
|
|
|
DelayBasePoint *btcec.PublicKey
|
|
|
|
}
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
// OpenChannel encapsulates the persistent and dynamic state of an open channel
|
|
|
|
// with a remote node. An open channel supports several options for on-disk
|
|
|
|
// serialization depending on the exact context. Full (upon channel creation)
|
|
|
|
// state commitments, and partial (due to a commitment update) writes are
|
|
|
|
// supported. Each partial write due to a state update appends the new update
|
|
|
|
// to an on-disk log, which can then subsequently be queried in order to
|
|
|
|
// "time-travel" to a prior state.
|
2015-12-26 21:35:15 +03:00
|
|
|
type OpenChannel struct {
|
2017-07-29 20:58:39 +03:00
|
|
|
// ChanType denotes which type of channel this is.
|
|
|
|
ChanType ChannelType
|
|
|
|
|
|
|
|
// ChainHash is a hash which represents the blockchain that this
|
|
|
|
// channel will be opened within. This value is typically the genesis
|
|
|
|
// hash. In the case that the original chain went through a contentious
|
|
|
|
// hard-fork, then this value will be tweaked using the unique fork
|
|
|
|
// point on each branch.
|
|
|
|
ChainHash chainhash.Hash
|
|
|
|
|
2017-07-29 05:40:52 +03:00
|
|
|
// FundingOutpoint is the outpoint of the final funding transaction.
|
|
|
|
// This value uniquely and globally identities the channel within the
|
|
|
|
// target blockchain as specified by the chain hash parameter.
|
|
|
|
FundingOutpoint wire.OutPoint
|
2017-07-29 20:58:39 +03:00
|
|
|
|
|
|
|
// ShortChanID encodes the exact location in the chain in which the
|
2017-06-16 23:28:26 +03:00
|
|
|
// channel was initially confirmed. This includes: the block height,
|
|
|
|
// transaction index, and the output within the target transaction.
|
|
|
|
ShortChanID lnwire.ShortChannelID
|
2017-05-11 02:44:40 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// IsPending indicates whether a channel's funding transaction has been
|
|
|
|
// confirmed.
|
|
|
|
IsPending bool
|
|
|
|
|
|
|
|
// IsInitiator is a bool which indicates if we were the original
|
|
|
|
// initiator for the channel. This value may affect how higher levels
|
|
|
|
// negotiate fees, or close the channel.
|
|
|
|
IsInitiator bool
|
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
// FundingBroadcastHeight is the height in which the funding
|
|
|
|
// transaction was broadcast. This value can be used by higher level
|
|
|
|
// sub-systems to determine if a channel is stale and/or should have
|
|
|
|
// been confirmed before a certain height.
|
|
|
|
FundingBroadcastHeight uint32
|
|
|
|
|
2016-10-26 02:11:23 +03:00
|
|
|
// IdentityPub is the identity public key of the remote node this
|
|
|
|
// channel has been established with.
|
|
|
|
IdentityPub *btcec.PublicKey
|
2015-12-26 21:35:15 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// LocalChanCfg is the channel configuration for the local node.
|
|
|
|
LocalChanCfg ChannelConfig
|
|
|
|
|
|
|
|
// RemoteChanCfg is the channel configuration for the remote node.
|
|
|
|
RemoteChanCfg ChannelConfig
|
2016-11-16 05:52:55 +03:00
|
|
|
|
2017-05-17 04:43:56 +03:00
|
|
|
// FeePerKw is the min satoshis/kilo-weight that should be paid within
|
|
|
|
// the commitment transaction for the entire duration of the channel's
|
2016-11-16 05:52:55 +03:00
|
|
|
// lifetime. This field may be updated during normal operation of the
|
|
|
|
// channel as on-chain conditions change.
|
2017-05-17 04:43:56 +03:00
|
|
|
FeePerKw btcutil.Amount
|
2015-12-26 21:35:15 +03:00
|
|
|
|
2016-11-16 05:52:55 +03:00
|
|
|
// Capacity is the total capacity of this channel.
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// LocalBalance is the current available settled balance within the
|
2016-11-16 05:52:55 +03:00
|
|
|
// channel directly spendable by us.
|
2017-07-29 20:58:39 +03:00
|
|
|
LocalBalance btcutil.Amount
|
2016-11-16 05:52:55 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// RemoteBalance is the current available settled balance within the
|
2016-11-16 05:52:55 +03:00
|
|
|
// channel directly spendable by the remote node.
|
2017-07-29 20:58:39 +03:00
|
|
|
RemoteBalance btcutil.Amount
|
2015-12-26 21:35:15 +03:00
|
|
|
|
2017-05-01 08:53:54 +03:00
|
|
|
// CommitFee is the amount calculated to be paid in fees for the
|
2017-05-17 04:43:56 +03:00
|
|
|
// current set of commitment transactions. The fee amount is persisted
|
|
|
|
// with the channel in order to allow the fee amount to be removed and
|
|
|
|
// recalculated with each channel state update, including updates that
|
|
|
|
// happen after a system restart.
|
2017-05-01 08:53:54 +03:00
|
|
|
CommitFee btcutil.Amount
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// CommitKey is the latest version of the commitment state, broadcast
|
|
|
|
// able by us.
|
|
|
|
CommitTx wire.MsgTx
|
2015-12-26 21:35:15 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// CommitSig is one half of the signature required to fully complete
|
|
|
|
// the script for the commitment transaction above. This is the
|
|
|
|
// signature signed by the remote party for our version of the
|
|
|
|
// commitment transactions.
|
|
|
|
CommitSig []byte
|
2015-12-26 21:35:15 +03:00
|
|
|
|
2017-01-24 04:15:14 +03:00
|
|
|
// NumConfsRequired is the number of confirmations a channel's funding
|
2017-07-29 20:58:39 +03:00
|
|
|
// transaction must have received in order to be considered available
|
|
|
|
// for normal transactional use.
|
2017-01-24 04:15:14 +03:00
|
|
|
NumConfsRequired uint16
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// RemoteCurrentRevocation is the current revocation for their
|
|
|
|
// commitment transaction. However, since this the derived public key,
|
|
|
|
// we don't yet have the private key so we aren't yet able to verify
|
|
|
|
// that it's actually in the hash chain.
|
|
|
|
RemoteCurrentRevocation *btcec.PublicKey
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// RemoteNextRevocation is the revocation key to be used for the *next*
|
|
|
|
// commitment transaction we create for the local node. Within the
|
|
|
|
// specification, this value is referred to as the
|
|
|
|
// per-commitment-point.
|
|
|
|
RemoteNextRevocation *btcec.PublicKey
|
2016-12-14 17:01:48 +03:00
|
|
|
|
|
|
|
// RevocationProducer is used to generate the revocation in such a way
|
|
|
|
// that remote side might store it efficiently and have the ability to
|
|
|
|
// restore the revocation by index if needed. Current implementation of
|
|
|
|
// secret producer is shachain producer.
|
|
|
|
RevocationProducer shachain.Producer
|
|
|
|
|
|
|
|
// RevocationStore is used to efficiently store the revocations for
|
|
|
|
// previous channels states sent to us by remote side. Current
|
|
|
|
// implementation of secret store is shachain store.
|
|
|
|
RevocationStore shachain.Store
|
2015-12-26 21:35:15 +03:00
|
|
|
|
2016-11-16 05:52:55 +03:00
|
|
|
// NumUpdates is the total number of updates conducted within this
|
|
|
|
// channel.
|
|
|
|
NumUpdates uint64
|
|
|
|
|
|
|
|
// TotalSatoshisSent is the total number of satoshis we've sent within
|
|
|
|
// this channel.
|
|
|
|
TotalSatoshisSent uint64
|
|
|
|
|
|
|
|
// TotalSatoshisReceived is the total number of satoshis we've received
|
|
|
|
// within this channel.
|
2015-12-26 21:35:15 +03:00
|
|
|
TotalSatoshisReceived uint64
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// Htlcs is the list of active, uncleared HTLCs currently pending
|
2016-11-16 05:52:55 +03:00
|
|
|
// within the channel.
|
2016-09-07 05:17:34 +03:00
|
|
|
Htlcs []*HTLC
|
|
|
|
|
2016-03-24 10:00:22 +03:00
|
|
|
// TODO(roasbeef): eww
|
|
|
|
Db *DB
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
sync.RWMutex
|
2015-12-26 02:00:20 +03:00
|
|
|
}
|
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
// FullSync serializes, and writes to disk the *full* channel state, using
|
|
|
|
// both the active channel bucket to store the prefixed column fields, and the
|
|
|
|
// remote node's ID to store the remainder of the channel state.
|
|
|
|
func (c *OpenChannel) FullSync() error {
|
2016-09-07 05:17:34 +03:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
return c.Db.Update(c.fullSync)
|
2016-10-27 00:47:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// fullSync is an internal versino of the FullSync method which allows callers
|
|
|
|
// to sync the contents of an OpenChannel while re-using an existing database
|
|
|
|
// transaction.
|
|
|
|
func (c *OpenChannel) fullSync(tx *bolt.Tx) error {
|
|
|
|
// TODO(roasbeef): add helper funcs to create scoped update
|
|
|
|
// First fetch the top level bucket which stores all data related to
|
|
|
|
// current, active channels.
|
|
|
|
chanBucket, err := tx.CreateBucketIfNotExists(openChannelBucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Within this top level bucket, fetch the bucket dedicated to storing
|
|
|
|
// open channel data specific to the remote node.
|
|
|
|
nodePub := c.IdentityPub.SerializeCompressed()
|
|
|
|
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(nodePub)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add this channel ID to the node's active channel index if
|
|
|
|
// it doesn't already exist.
|
2017-02-08 06:54:40 +03:00
|
|
|
chanIndexBucket, err := nodeChanBucket.CreateBucketIfNotExists(chanIDBucket)
|
2016-10-27 00:47:02 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &c.FundingOutpoint); err != nil {
|
2016-10-27 00:47:02 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-02-08 06:54:40 +03:00
|
|
|
if chanIndexBucket.Get(b.Bytes()) == nil {
|
|
|
|
if err := chanIndexBucket.Put(b.Bytes(), nil); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-10-27 00:47:02 +03:00
|
|
|
}
|
2016-06-21 07:39:50 +03:00
|
|
|
|
2016-10-27 00:47:02 +03:00
|
|
|
return putOpenChannel(chanBucket, nodeChanBucket, c)
|
|
|
|
}
|
|
|
|
|
2017-01-23 10:31:01 +03:00
|
|
|
// SyncPending writes the contents of the channel to the database while it's in
|
|
|
|
// the pending (waiting for funding confirmation) state. The IsPending flag
|
|
|
|
// will be set to true. When the channel's funding transaction is confirmed,
|
|
|
|
// the channel should be marked as "open" and the IsPending flag set to false.
|
|
|
|
// Note that this function also creates a LinkNode relationship between this
|
|
|
|
// newly created channel and a new LinkNode instance. This allows listing all
|
|
|
|
// channels in the database globally, or according to the LinkNode they were
|
|
|
|
// created with.
|
2016-10-27 00:47:02 +03:00
|
|
|
//
|
|
|
|
// TODO(roasbeef): addr param should eventually be a lnwire.NetAddress type
|
|
|
|
// that includes service bits.
|
2017-06-06 01:02:27 +03:00
|
|
|
func (c *OpenChannel) SyncPending(addr *net.TCPAddr, pendingHeight uint32) error {
|
2016-10-27 00:47:02 +03:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
c.FundingBroadcastHeight = pendingHeight
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
return c.Db.Update(func(tx *bolt.Tx) error {
|
2016-10-27 00:47:02 +03:00
|
|
|
// First, sync all the persistent channel state to disk.
|
|
|
|
if err := c.fullSync(tx); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-10-27 00:47:02 +03:00
|
|
|
nodeInfoBucket, err := tx.CreateBucketIfNotExists(nodeInfoBucket)
|
2016-06-21 07:39:50 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-10-27 00:47:02 +03:00
|
|
|
|
2017-05-11 02:44:40 +03:00
|
|
|
// If a LinkNode for this identity public key already exists,
|
|
|
|
// then we can exit early.
|
2016-10-27 00:47:02 +03:00
|
|
|
nodePub := c.IdentityPub.SerializeCompressed()
|
|
|
|
if nodeInfoBucket.Get(nodePub) != nil {
|
|
|
|
return nil
|
2016-06-21 07:39:50 +03:00
|
|
|
}
|
|
|
|
|
2016-10-27 00:47:02 +03:00
|
|
|
// Next, we need to establish a (possibly) new LinkNode
|
2017-05-11 02:44:40 +03:00
|
|
|
// relationship for this channel. The LinkNode metadata
|
|
|
|
// contains reachability, up-time, and service bits related
|
|
|
|
// information.
|
|
|
|
// TODO(roasbeef): net info should be in lnwire.NetAddress
|
2016-10-27 00:47:02 +03:00
|
|
|
linkNode := c.Db.NewLinkNode(wire.MainNet, c.IdentityPub, addr)
|
|
|
|
|
|
|
|
return putLinkNode(nodeInfoBucket, linkNode)
|
2016-06-21 07:39:50 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
// UpdateCommitment updates the on-disk state of our currently broadcastable
|
|
|
|
// commitment state. This method is to be called once we have revoked our prior
|
|
|
|
// commitment state, accepting the new state as defined by the passed
|
|
|
|
// parameters.
|
|
|
|
func (c *OpenChannel) UpdateCommitment(newCommitment *wire.MsgTx,
|
|
|
|
newSig []byte, delta *ChannelDelta) error {
|
|
|
|
|
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
return c.Db.Update(func(tx *bolt.Tx) error {
|
2016-07-13 03:26:49 +03:00
|
|
|
chanBucket, err := tx.CreateBucketIfNotExists(openChannelBucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-10-26 02:11:23 +03:00
|
|
|
id := c.IdentityPub.SerializeCompressed()
|
2016-09-07 05:17:34 +03:00
|
|
|
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
|
2016-07-13 03:26:49 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
// TODO(roasbeef): modify the funcs below to take values
|
|
|
|
// directly, otherwise need to roll back to prior state. Could
|
|
|
|
// also make copy above, then modify to pass in.
|
2017-07-29 20:58:39 +03:00
|
|
|
c.CommitTx = *newCommitment
|
|
|
|
c.CommitSig = newSig
|
|
|
|
c.LocalBalance = delta.LocalBalance
|
|
|
|
c.RemoteBalance = delta.RemoteBalance
|
2017-02-23 22:07:01 +03:00
|
|
|
c.NumUpdates = delta.UpdateNum
|
2016-09-07 05:17:34 +03:00
|
|
|
c.Htlcs = delta.Htlcs
|
2017-05-01 08:53:54 +03:00
|
|
|
c.CommitFee = delta.CommitFee
|
2017-07-14 21:38:35 +03:00
|
|
|
c.FeePerKw = delta.FeePerKw
|
2016-09-07 05:17:34 +03:00
|
|
|
|
|
|
|
// First we'll write out the current latest dynamic channel
|
|
|
|
// state: the current channel balance, the number of updates,
|
|
|
|
// and our latest commitment transaction+sig.
|
|
|
|
// TODO(roasbeef): re-make schema s.t this is a single put
|
|
|
|
if err := putChanCapacity(chanBucket, c); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-11-16 10:59:55 +03:00
|
|
|
if err := putChanAmountsTransferred(chanBucket, c); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
if err := putChanNumUpdates(chanBucket, c); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-05-01 08:53:54 +03:00
|
|
|
if err := putChanCommitFee(chanBucket, c); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-14 21:38:35 +03:00
|
|
|
if err := putChanFeePerKw(chanBucket, c); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
if err := putChanCommitTxns(nodeChanBucket, c); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := putCurrentHtlcs(nodeChanBucket, delta.Htlcs,
|
|
|
|
&c.FundingOutpoint); err != nil {
|
2016-07-13 03:26:49 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// HTLC is the on-disk representation of a hash time-locked contract. HTLCs
|
2016-09-03 04:51:34 +03:00
|
|
|
// are contained within ChannelDeltas which encode the current state of the
|
|
|
|
// commitment between state updates.
|
|
|
|
type HTLC struct {
|
2017-07-29 21:18:12 +03:00
|
|
|
// Signature is the signature for the second level covenant transaction
|
|
|
|
// for this HTLC. The second level transaction is a timeout tx in the
|
|
|
|
// case that this is an outgoing HTLC, and a success tx in the case
|
|
|
|
// that this is an incoming HTLC.
|
|
|
|
//
|
|
|
|
// TODO(roasbeef): make [64]byte instead?
|
|
|
|
Signature []byte
|
2016-09-03 04:51:34 +03:00
|
|
|
|
|
|
|
// RHash is the payment hash of the HTLC.
|
|
|
|
RHash [32]byte
|
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
// Amt is the amount of satoshis this HTLC escrows.
|
|
|
|
Amt btcutil.Amount
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
// RefundTimeout is the absolute timeout on the HTLC that the sender
|
|
|
|
// must wait before reclaiming the funds in limbo.
|
|
|
|
RefundTimeout uint32
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
// OutputIndex is the output index for this particular HTLC output
|
|
|
|
// within the commitment transaction.
|
2017-07-29 21:18:12 +03:00
|
|
|
OutputIndex int32
|
|
|
|
|
|
|
|
// Incoming denotes whether we're the receiver or the sender of this
|
|
|
|
// HTLC.
|
|
|
|
Incoming bool
|
2016-09-07 05:17:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy returns a full copy of the target HTLC.
|
|
|
|
func (h *HTLC) Copy() HTLC {
|
|
|
|
clone := HTLC{
|
2017-07-30 03:40:14 +03:00
|
|
|
Incoming: h.Incoming,
|
|
|
|
Amt: h.Amt,
|
|
|
|
RefundTimeout: h.RefundTimeout,
|
|
|
|
OutputIndex: h.OutputIndex,
|
2016-09-07 05:17:34 +03:00
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
copy(clone.Signature[:], h.Signature)
|
2016-09-07 05:17:34 +03:00
|
|
|
copy(clone.RHash[:], h.RHash[:])
|
|
|
|
|
|
|
|
return clone
|
2016-09-03 04:51:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// ChannelDelta is a snapshot of the commitment state at a particular point in
|
|
|
|
// the commitment chain. With each state transition, a snapshot of the current
|
2017-03-25 02:07:34 +03:00
|
|
|
// state along with all non-settled HTLCs are recorded. These snapshots detail
|
|
|
|
// the state of the _remote_ party's commitment at a particular state number.
|
|
|
|
// For ourselves (the local node) we ONLY store our most recent (unrevoked)
|
|
|
|
// state for safety purposes.
|
2016-09-03 04:51:34 +03:00
|
|
|
type ChannelDelta struct {
|
2017-03-25 02:07:34 +03:00
|
|
|
// LocalBalance is our current balance at this particular update
|
|
|
|
// number.
|
|
|
|
LocalBalance btcutil.Amount
|
|
|
|
|
|
|
|
// RemoteBalanceis the balance of the remote node at this particular
|
|
|
|
// update number.
|
2016-09-03 04:51:34 +03:00
|
|
|
RemoteBalance btcutil.Amount
|
|
|
|
|
2017-05-01 08:53:54 +03:00
|
|
|
// CommitFee is the fee that has been subtracted from the channel
|
|
|
|
// initiator's balance at this point in the commitment chain.
|
|
|
|
CommitFee btcutil.Amount
|
|
|
|
|
2017-07-14 21:38:35 +03:00
|
|
|
// FeePerKw is the fee per kw used to calculate the commit fee at this point
|
|
|
|
// in the commit chain.
|
|
|
|
FeePerKw btcutil.Amount
|
|
|
|
|
2017-03-25 02:07:34 +03:00
|
|
|
// UpdateNum is the update number that this ChannelDelta represents the
|
|
|
|
// total number of commitment updates to this point. This can be viewed
|
|
|
|
// as sort of a "commitment height" as this number is monotonically
|
|
|
|
// increasing.
|
|
|
|
UpdateNum uint64
|
2016-12-22 23:49:30 +03:00
|
|
|
|
2017-03-25 02:07:34 +03:00
|
|
|
// Htlcs is the set of HTLC's that are pending at this particular
|
|
|
|
// commitment height.
|
2016-09-03 04:51:34 +03:00
|
|
|
Htlcs []*HTLC
|
|
|
|
}
|
|
|
|
|
2017-07-29 21:24:03 +03:00
|
|
|
// InsertNextRevocation inserts the _next_ commitment point (revocation) into
|
|
|
|
// the database, and also modifies the internal RemoteNextRevocation attribute
|
|
|
|
// to point to the passed key. This method is to be using during final channel
|
|
|
|
// set up, _after_ the channel has been fully confirmed.
|
|
|
|
//
|
|
|
|
// NOTE: If this method isn't called, then the target channel won't be able to
|
|
|
|
// propose new states for the commitment state of the remote party.
|
|
|
|
func (c *OpenChannel) InsertNextRevocation(revKey *btcec.PublicKey) error {
|
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
|
|
|
return c.Db.Update(func(tx *bolt.Tx) error {
|
|
|
|
chanBucket, err := tx.CreateBucketIfNotExists(openChannelBucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
id := c.IdentityPub.SerializeCompressed()
|
|
|
|
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
c.RemoteNextRevocation = revKey
|
|
|
|
return putChanRevocationState(nodeChanBucket, c)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
// AppendToRevocationLog records the new state transition within an on-disk
|
|
|
|
// append-only log which records all state transitions by the remote peer. In
|
|
|
|
// the case of an uncooperative broadcast of a prior state by the remote peer,
|
|
|
|
// this log can be consulted in order to reconstruct the state needed to
|
|
|
|
// rectify the situation.
|
|
|
|
func (c *OpenChannel) AppendToRevocationLog(delta *ChannelDelta) error {
|
2016-11-28 05:32:45 +03:00
|
|
|
return c.Db.Update(func(tx *bolt.Tx) error {
|
2016-09-03 04:51:34 +03:00
|
|
|
chanBucket, err := tx.CreateBucketIfNotExists(openChannelBucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-10-26 02:11:23 +03:00
|
|
|
id := c.IdentityPub.SerializeCompressed()
|
2016-09-03 04:51:34 +03:00
|
|
|
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
|
2016-09-07 05:17:34 +03:00
|
|
|
if err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
|
2016-12-14 17:01:48 +03:00
|
|
|
// Persist the latest preimage state to disk as the remote peer
|
|
|
|
// has just added to our local preimage store, and
|
|
|
|
// given us a new pending revocation key.
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := putChanRevocationState(nodeChanBucket, c); err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:01:48 +03:00
|
|
|
// With the current preimage producer/store state updated,
|
|
|
|
// append a new log entry recording this the delta of this state
|
|
|
|
// transition.
|
2016-09-03 04:51:34 +03:00
|
|
|
// TODO(roasbeef): could make the deltas relative, would save
|
|
|
|
// space, but then tradeoff for more disk-seeks to recover the
|
|
|
|
// full state.
|
|
|
|
logKey := channelLogBucket
|
|
|
|
logBucket, err := nodeChanBucket.CreateBucketIfNotExists(logKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 05:40:52 +03:00
|
|
|
return appendChannelLogEntry(logBucket, delta, &c.FundingOutpoint)
|
2016-09-03 04:51:34 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-03-25 02:07:34 +03:00
|
|
|
// RevocationLogTail returns the "tail", or the end of the current revocation
|
|
|
|
// log. This entry represents the last previous state for the remote node's
|
|
|
|
// commitment chain. The ChannelDelta returned by this method will always lag
|
|
|
|
// one state behind the most current (unrevoked) state of the remote node's
|
|
|
|
// commitment chain.
|
|
|
|
func (c *OpenChannel) RevocationLogTail() (*ChannelDelta, error) {
|
|
|
|
// If we haven't created any state updates yet, then we'll exit erly as
|
|
|
|
// there's nothing to be found on disk in the revocation bucket.
|
|
|
|
if c.NumUpdates == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var delta *ChannelDelta
|
|
|
|
if err := c.Db.View(func(tx *bolt.Tx) error {
|
|
|
|
chanBucket := tx.Bucket(openChannelBucket)
|
|
|
|
|
|
|
|
nodePub := c.IdentityPub.SerializeCompressed()
|
|
|
|
nodeChanBucket := chanBucket.Bucket(nodePub)
|
|
|
|
if nodeChanBucket == nil {
|
|
|
|
return ErrNoActiveChannels
|
|
|
|
}
|
|
|
|
|
|
|
|
logBucket := nodeChanBucket.Bucket(channelLogBucket)
|
2017-05-11 02:37:50 +03:00
|
|
|
if logBucket == nil {
|
2017-03-25 02:07:34 +03:00
|
|
|
return ErrNoPastDeltas
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we have the bucket that stores the revocation log from
|
|
|
|
// this channel, we'll jump to the _last_ key in bucket. As we
|
|
|
|
// store the update number on disk in a big-endian format,
|
|
|
|
// this'll retrieve the latest entry.
|
|
|
|
cursor := logBucket.Cursor()
|
|
|
|
_, tailLogEntry := cursor.Last()
|
|
|
|
logEntryReader := bytes.NewReader(tailLogEntry)
|
|
|
|
|
|
|
|
// Once we have the entry, we'll decode it into the channel
|
|
|
|
// delta pointer we created above.
|
|
|
|
var dbErr error
|
|
|
|
delta, dbErr = deserializeChannelDelta(logEntryReader)
|
|
|
|
if dbErr != nil {
|
|
|
|
return dbErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return delta, nil
|
|
|
|
}
|
|
|
|
|
2016-11-28 06:10:05 +03:00
|
|
|
// CommitmentHeight returns the current commitment height. The commitment
|
|
|
|
// height represents the number of updates to the commitment state to data.
|
|
|
|
// This value is always monotonically increasing. This method is provided in
|
|
|
|
// order to allow multiple instances of a particular open channel to obtain a
|
|
|
|
// consistent view of the number of channel updates to data.
|
|
|
|
func (c *OpenChannel) CommitmentHeight() (uint64, error) {
|
|
|
|
// TODO(roasbeef): this is super hacky, remedy during refactor!!!
|
|
|
|
o := &OpenChannel{
|
2017-07-29 05:40:52 +03:00
|
|
|
FundingOutpoint: c.FundingOutpoint,
|
2016-11-28 06:10:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
err := c.Db.View(func(tx *bolt.Tx) error {
|
2017-01-13 08:01:50 +03:00
|
|
|
// Get the bucket dedicated to storing the metadata for open
|
2016-11-28 06:10:05 +03:00
|
|
|
// channels.
|
|
|
|
openChanBucket := tx.Bucket(openChannelBucket)
|
|
|
|
if openChanBucket == nil {
|
|
|
|
return ErrNoActiveChannels
|
|
|
|
}
|
|
|
|
|
|
|
|
return fetchChanNumUpdates(openChanBucket, o)
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return o.NumUpdates, nil
|
|
|
|
}
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
// FindPreviousState scans through the append-only log in an attempt to recover
|
|
|
|
// the previous channel state indicated by the update number. This method is
|
|
|
|
// intended to be used for obtaining the relevant data needed to claim all
|
|
|
|
// funds rightfully spendable in the case of an on-chain broadcast of the
|
|
|
|
// commitment transaction.
|
|
|
|
func (c *OpenChannel) FindPreviousState(updateNum uint64) (*ChannelDelta, error) {
|
|
|
|
delta := &ChannelDelta{}
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
err := c.Db.View(func(tx *bolt.Tx) error {
|
2016-09-03 04:51:34 +03:00
|
|
|
chanBucket := tx.Bucket(openChannelBucket)
|
|
|
|
|
2016-10-26 02:11:23 +03:00
|
|
|
nodePub := c.IdentityPub.SerializeCompressed()
|
|
|
|
nodeChanBucket := chanBucket.Bucket(nodePub)
|
2016-09-03 04:51:34 +03:00
|
|
|
if nodeChanBucket == nil {
|
|
|
|
return ErrNoActiveChannels
|
|
|
|
}
|
|
|
|
|
|
|
|
logBucket := nodeChanBucket.Bucket(channelLogBucket)
|
2017-05-11 02:37:50 +03:00
|
|
|
if logBucket == nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return ErrNoPastDeltas
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
2017-07-29 05:40:52 +03:00
|
|
|
delta, err = fetchChannelLogEntry(logBucket, &c.FundingOutpoint,
|
2017-02-16 16:03:24 +03:00
|
|
|
updateNum)
|
2016-09-03 04:51:34 +03:00
|
|
|
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return delta, nil
|
|
|
|
}
|
|
|
|
|
2017-05-05 01:19:21 +03:00
|
|
|
// ClosureType is an enum like structure that details exactly _how_ a channel
|
|
|
|
// was closed. Three closure types are currently possible: cooperative, force,
|
|
|
|
// and breach.
|
|
|
|
type ClosureType uint8
|
|
|
|
|
|
|
|
const (
|
2017-05-05 03:44:10 +03:00
|
|
|
// CooperativeClose indicates that a channel has been closed
|
|
|
|
// cooperatively. This means that both channel peers were online and
|
|
|
|
// signed a new transaction paying out the settled balance of the
|
|
|
|
// contract.
|
2017-05-05 01:19:21 +03:00
|
|
|
CooperativeClose ClosureType = iota
|
|
|
|
|
2017-05-05 03:44:10 +03:00
|
|
|
// ForceClose indicates that one peer unilaterally broadcast their
|
|
|
|
// current commitment state on-chain.
|
2017-05-05 01:19:21 +03:00
|
|
|
ForceClose
|
|
|
|
|
2017-05-05 03:44:10 +03:00
|
|
|
// BreachClose indicates that one peer attempted to broadcast a prior
|
2017-05-05 01:19:21 +03:00
|
|
|
// _revoked_ channel state.
|
|
|
|
BreachClose
|
2017-06-08 20:48:07 +03:00
|
|
|
|
|
|
|
// FundingCanceled indicates that the channel never was fully opened before it
|
|
|
|
// was marked as closed in the database. This can happen if we or the remote
|
|
|
|
// fail at some point during the opening workflow, or we timeout waiting for
|
|
|
|
// the funding transaction to be confirmed.
|
|
|
|
FundingCanceled
|
2017-05-05 01:19:21 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// ChannelCloseSummary contains the final state of a channel at the point it
|
|
|
|
// was close. Once a channel is closed, all the information pertaining to that
|
|
|
|
// channel within the openChannelBucket is deleted, and a compact summary is
|
|
|
|
// but in place instead.
|
|
|
|
type ChannelCloseSummary struct {
|
|
|
|
// ChanPoint is the outpoint for this channel's funding transaction,
|
|
|
|
// and is used as a unique identifier for the channel.
|
|
|
|
ChanPoint wire.OutPoint
|
|
|
|
|
|
|
|
// ClosingTXID is the txid of the transaction which ultimately closed
|
|
|
|
// this channel.
|
|
|
|
ClosingTXID chainhash.Hash
|
|
|
|
|
|
|
|
// RemotePub is the public key of the remote peer that we formerly had
|
|
|
|
// a channel with.
|
|
|
|
RemotePub *btcec.PublicKey
|
|
|
|
|
|
|
|
// Capacity was the total capacity of the channel.
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
|
2017-05-15 05:02:59 +03:00
|
|
|
// SettledBalance is our total balance settled balance at the time of
|
|
|
|
// channel closure. This _does not_ include the sum of any outputs that
|
|
|
|
// have been time-locked as a result of the unilateral channel closure.
|
|
|
|
SettledBalance btcutil.Amount
|
|
|
|
|
|
|
|
// TimeLockedBalance is the sum of all the time-locked outputs at the
|
|
|
|
// time of channel closure. If we triggered the force closure of this
|
|
|
|
// channel, then this value will be non-zero if our settled output is
|
|
|
|
// above the dust limit. If we were on the receiving side of a channel
|
|
|
|
// force closure, then this value will be non-zero if we had any
|
|
|
|
// outstanding outgoing HTLC's at the time of channel closure.
|
|
|
|
TimeLockedBalance btcutil.Amount
|
2017-05-05 01:19:21 +03:00
|
|
|
|
|
|
|
// CloseType details exactly _how_ the channel was closed. Three
|
|
|
|
// closure types are possible: cooperative, force, and breach.
|
|
|
|
CloseType ClosureType
|
|
|
|
|
|
|
|
// IsPending indicates whether this channel is in the 'pending close'
|
|
|
|
// state, which means the channel closing transaction has been
|
|
|
|
// broadcast, but not confirmed yet or has not yet been fully resolved.
|
|
|
|
// In the case of a channel that has been cooperatively closed, it will
|
|
|
|
// no longer be considered pending as soon as the closing transaction
|
|
|
|
// has been confirmed. However, for channel that have been force
|
|
|
|
// closed, they'll stay marked as "pending" until _all_ the pending
|
|
|
|
// funds have been swept.
|
|
|
|
IsPending bool
|
2017-05-17 04:43:56 +03:00
|
|
|
|
|
|
|
// TODO(roasbeef): also store short_chan_id?
|
2017-05-05 01:19:21 +03:00
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
// CloseChannel closes a previously active lightning channel. Closing a channel
|
|
|
|
// entails deleting all saved state within the database concerning this
|
2017-05-05 01:19:21 +03:00
|
|
|
// channel. This method also takes a struct that summarizes the state of the
|
|
|
|
// channel at closing, this compact representation will be the only component
|
|
|
|
// of a channel left over after a full closing.
|
|
|
|
func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary) error {
|
2016-11-28 05:32:45 +03:00
|
|
|
return c.Db.Update(func(tx *bolt.Tx) error {
|
2017-02-03 03:59:14 +03:00
|
|
|
// First fetch the top level bucket which stores all data
|
|
|
|
// related to current, active channels.
|
2016-06-23 02:15:07 +03:00
|
|
|
chanBucket := tx.Bucket(openChannelBucket)
|
|
|
|
if chanBucket == nil {
|
|
|
|
return ErrNoChanDBExists
|
|
|
|
}
|
|
|
|
|
2017-02-03 03:59:14 +03:00
|
|
|
// Within this top level bucket, fetch the bucket dedicated to
|
|
|
|
// storing open channel data specific to the remote node.
|
2016-10-26 02:11:23 +03:00
|
|
|
nodePub := c.IdentityPub.SerializeCompressed()
|
|
|
|
nodeChanBucket := chanBucket.Bucket(nodePub)
|
2016-06-23 02:15:07 +03:00
|
|
|
if nodeChanBucket == nil {
|
|
|
|
return ErrNoActiveChannels
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete this channel ID from the node's active channel index.
|
|
|
|
chanIndexBucket := nodeChanBucket.Bucket(chanIDBucket)
|
|
|
|
if chanIndexBucket == nil {
|
|
|
|
return ErrNoActiveChannels
|
|
|
|
}
|
2016-12-20 03:49:42 +03:00
|
|
|
|
2017-02-03 03:59:14 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &c.FundingOutpoint); err != nil {
|
2017-02-03 03:59:14 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-12-20 03:49:42 +03:00
|
|
|
// If this channel isn't found within the channel index bucket,
|
|
|
|
// then it has already been deleted. So we can exit early as
|
|
|
|
// there isn't any more work for us to do here.
|
2016-06-23 02:15:07 +03:00
|
|
|
outPointBytes := b.Bytes()
|
2016-12-20 03:49:42 +03:00
|
|
|
if chanIndexBucket.Get(outPointBytes) == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we can safely delete the channel from the index
|
|
|
|
// without running into any boltdb related errors by repeated
|
|
|
|
// deletion attempts.
|
|
|
|
if err := chanIndexBucket.Delete(outPointBytes); err != nil {
|
2016-06-23 02:15:07 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that the index to this channel has been deleted, purge
|
2017-01-13 08:01:50 +03:00
|
|
|
// the remaining channel metadata from the database.
|
2016-06-23 02:15:07 +03:00
|
|
|
if err := deleteOpenChannel(chanBucket, nodeChanBucket,
|
2017-07-29 05:40:52 +03:00
|
|
|
outPointBytes, &c.FundingOutpoint); err != nil {
|
2016-06-23 02:15:07 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-02-08 03:27:53 +03:00
|
|
|
// With the base channel data deleted, attempt to delte the
|
|
|
|
// information stored within the revocation log.
|
|
|
|
logBucket := nodeChanBucket.Bucket(channelLogBucket)
|
|
|
|
if logBucket != nil {
|
2017-07-29 05:40:52 +03:00
|
|
|
err := wipeChannelLogEntries(logBucket, &c.FundingOutpoint)
|
2017-02-08 03:27:53 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
// Finally, create a summary of this channel in the closed
|
|
|
|
// channel bucket for this node.
|
2017-05-05 01:19:21 +03:00
|
|
|
return putChannelCloseSummary(tx, outPointBytes, summary)
|
2016-06-23 02:15:07 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-06-23 08:03:09 +03:00
|
|
|
// ChannelSnapshot is a frozen snapshot of the current channel state. A
|
|
|
|
// snapshot is detached from the original channel that generated it, providing
|
|
|
|
// read-only access to the current or prior state of an active channel.
|
2016-03-24 08:39:52 +03:00
|
|
|
type ChannelSnapshot struct {
|
2016-10-26 02:11:23 +03:00
|
|
|
RemoteIdentity btcec.PublicKey
|
2016-06-23 08:03:09 +03:00
|
|
|
|
|
|
|
ChannelPoint *wire.OutPoint
|
|
|
|
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
LocalBalance btcutil.Amount
|
|
|
|
RemoteBalance btcutil.Amount
|
|
|
|
|
|
|
|
NumUpdates uint64
|
|
|
|
|
|
|
|
TotalSatoshisSent uint64
|
|
|
|
TotalSatoshisReceived uint64
|
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
Htlcs []HTLC
|
2016-06-23 08:03:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Snapshot returns a read-only snapshot of the current channel state. This
|
|
|
|
// snapshot includes information concerning the current settled balance within
|
2017-01-13 08:01:50 +03:00
|
|
|
// the channel, metadata detailing total flows, and any outstanding HTLCs.
|
2016-06-23 08:03:09 +03:00
|
|
|
func (c *OpenChannel) Snapshot() *ChannelSnapshot {
|
2016-09-07 05:17:34 +03:00
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
|
|
|
|
2016-06-23 08:03:09 +03:00
|
|
|
snapshot := &ChannelSnapshot{
|
2016-10-26 02:11:23 +03:00
|
|
|
RemoteIdentity: *c.IdentityPub,
|
2017-07-29 05:40:52 +03:00
|
|
|
ChannelPoint: &c.FundingOutpoint,
|
2016-06-23 08:03:09 +03:00
|
|
|
Capacity: c.Capacity,
|
2017-07-29 20:58:39 +03:00
|
|
|
LocalBalance: c.LocalBalance,
|
|
|
|
RemoteBalance: c.RemoteBalance,
|
2016-06-23 08:03:09 +03:00
|
|
|
NumUpdates: c.NumUpdates,
|
|
|
|
TotalSatoshisSent: c.TotalSatoshisSent,
|
|
|
|
TotalSatoshisReceived: c.TotalSatoshisReceived,
|
|
|
|
}
|
|
|
|
|
2017-01-13 08:01:50 +03:00
|
|
|
// Copy over the current set of HTLCs to ensure the caller can't
|
2016-09-07 05:17:34 +03:00
|
|
|
// mutate our internal state.
|
|
|
|
snapshot.Htlcs = make([]HTLC, len(c.Htlcs))
|
|
|
|
for i, h := range c.Htlcs {
|
|
|
|
snapshot.Htlcs[i] = h.Copy()
|
|
|
|
}
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
return snapshot
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
|
|
|
|
2017-05-05 01:19:21 +03:00
|
|
|
func putChannelCloseSummary(tx *bolt.Tx, chanID []byte,
|
|
|
|
summary *ChannelCloseSummary) error {
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
closedChanBucket, err := tx.CreateBucketIfNotExists(closedChannelBucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-05-05 01:19:21 +03:00
|
|
|
var b bytes.Buffer
|
|
|
|
if err := serializeChannelCloseSummary(&b, summary); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return closedChanBucket.Put(chanID, b.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
func serializeChannelCloseSummary(w io.Writer, cs *ChannelCloseSummary) error {
|
|
|
|
if err := writeBool(w, cs.IsPending); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := writeOutpoint(w, &cs.ChanPoint); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err := w.Write(cs.ClosingTXID[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-05-15 05:02:59 +03:00
|
|
|
if err := binary.Write(w, byteOrder, cs.SettledBalance); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := binary.Write(w, byteOrder, cs.TimeLockedBalance); err != nil {
|
2017-05-05 01:19:21 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := binary.Write(w, byteOrder, cs.Capacity); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := w.Write([]byte{byte(cs.CloseType)}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
pub := cs.RemotePub.SerializeCompressed()
|
|
|
|
if _, err := w.Write(pub); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchChannelCloseSummary(tx *bolt.Tx,
|
|
|
|
chanID []byte) (*ChannelCloseSummary, error) {
|
|
|
|
|
|
|
|
closedChanBucket, err := tx.CreateBucketIfNotExists(closedChannelBucket)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
summaryBytes := closedChanBucket.Get(chanID)
|
|
|
|
if summaryBytes == nil {
|
|
|
|
return nil, fmt.Errorf("closed channel summary not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
summaryReader := bytes.NewReader(summaryBytes)
|
|
|
|
return deserializeCloseChannelSummary(summaryReader)
|
|
|
|
}
|
|
|
|
|
|
|
|
func deserializeCloseChannelSummary(r io.Reader) (*ChannelCloseSummary, error) {
|
|
|
|
c := &ChannelCloseSummary{}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
c.IsPending, err = readBool(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := readOutpoint(r, &c.ChanPoint); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if _, err := io.ReadFull(r, c.ClosingTXID[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-05-15 05:02:59 +03:00
|
|
|
if err := binary.Read(r, byteOrder, &c.SettledBalance); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := binary.Read(r, byteOrder, &c.TimeLockedBalance); err != nil {
|
2017-05-05 01:19:21 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := binary.Read(r, byteOrder, &c.Capacity); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var closeType [1]byte
|
|
|
|
if _, err := io.ReadFull(r, closeType[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
c.CloseType = ClosureType(closeType[0])
|
|
|
|
|
|
|
|
var pub [33]byte
|
|
|
|
if _, err := io.ReadFull(r, pub[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
c.RemotePub, err = btcec.ParsePubKey(pub[:], btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return c, nil
|
2016-06-23 02:15:07 +03:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
// putChannel serializes, and stores the current state of the channel in its
|
|
|
|
// entirety.
|
|
|
|
func putOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
|
2016-08-13 00:57:27 +03:00
|
|
|
channel *OpenChannel) error {
|
2015-12-26 03:00:44 +03:00
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
// First write out all the "common" fields using the field's prefix
|
2016-12-22 23:49:30 +03:00
|
|
|
// append with the channel's ID. These fields go into a top-level
|
|
|
|
// bucket to allow for ease of metric aggregation via efficient prefix
|
|
|
|
// scans.
|
2016-03-24 08:39:52 +03:00
|
|
|
if err := putChanCapacity(openChanBucket, channel); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-05-17 04:43:56 +03:00
|
|
|
if err := putChanFeePerKw(openChanBucket, channel); err != nil {
|
2016-03-24 08:39:52 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := putChanNumUpdates(openChanBucket, channel); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-11-16 10:59:55 +03:00
|
|
|
if err := putChanAmountsTransferred(openChanBucket, channel); err != nil {
|
2016-03-24 08:39:52 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-01-23 10:31:01 +03:00
|
|
|
if err := putChanIsPending(openChanBucket, channel); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-06-06 01:02:27 +03:00
|
|
|
if err := putChanConfInfo(openChanBucket, channel); err != nil {
|
2017-05-11 02:44:40 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-05-01 08:53:54 +03:00
|
|
|
if err := putChanCommitFee(openChanBucket, channel); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-12-26 03:00:44 +03:00
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
// Next, write out the fields of the channel update less frequently.
|
|
|
|
if err := putChannelIDs(nodeChanBucket, channel); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := putChanConfigs(nodeChanBucket, channel); err != nil {
|
2016-03-24 08:39:52 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := putChanCommitTxns(nodeChanBucket, channel); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-08-13 00:57:27 +03:00
|
|
|
if err := putChanFundingInfo(nodeChanBucket, channel); err != nil {
|
2016-03-24 08:39:52 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := putChanRevocationState(nodeChanBucket, channel); err != nil {
|
2015-12-26 03:00:44 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
if err := putCurrentHtlcs(nodeChanBucket, channel.Htlcs,
|
2017-07-29 05:40:52 +03:00
|
|
|
&channel.FundingOutpoint); err != nil {
|
2016-09-07 05:17:34 +03:00
|
|
|
return err
|
|
|
|
}
|
2015-12-26 03:00:44 +03:00
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
return nil
|
2015-12-26 03:00:44 +03:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
// fetchOpenChannel retrieves, and deserializes (including decrypting
|
|
|
|
// sensitive) the complete channel currently active with the passed nodeID.
|
2016-06-21 07:39:50 +03:00
|
|
|
func fetchOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
|
2016-08-13 00:57:27 +03:00
|
|
|
chanID *wire.OutPoint) (*OpenChannel, error) {
|
2015-12-26 09:12:31 +03:00
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
var err error
|
2016-06-21 07:39:50 +03:00
|
|
|
channel := &OpenChannel{
|
2017-07-29 05:40:52 +03:00
|
|
|
FundingOutpoint: *chanID,
|
2015-12-26 03:00:44 +03:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
// First, read out the fields of the channel update less frequently.
|
2016-09-07 05:17:34 +03:00
|
|
|
if err = fetchChannelIDs(nodeChanBucket, channel); err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read chan ID's: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err = fetchChanConfigs(nodeChanBucket, channel); err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to read chan config: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
if err = fetchChanCommitTxns(nodeChanBucket, channel); err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read commit txns: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
if err = fetchChanFundingInfo(nodeChanBucket, channel); err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read funding info: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err = fetchChanRevocationState(nodeChanBucket, channel); err != nil {
|
2016-12-14 17:01:48 +03:00
|
|
|
return nil, err
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
channel.Htlcs, err = fetchCurrentHtlcs(nodeChanBucket, chanID)
|
|
|
|
if err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read current htlc's: %v", err)
|
2015-12-26 03:00:44 +03:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
// With the existence of an open channel bucket with this node verified,
|
|
|
|
// perform a full read of the entire struct. Starting with the prefixed
|
|
|
|
// fields residing in the parent bucket.
|
2017-02-08 03:27:53 +03:00
|
|
|
// TODO(roasbeef): combine the below into channel config like key
|
2016-09-07 05:17:34 +03:00
|
|
|
if err = fetchChanCapacity(openChanBucket, channel); err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read chan capacity: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err = fetchChanMinFeePerKw(openChanBucket, channel); err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read fee-per-kb: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2016-09-07 05:17:34 +03:00
|
|
|
if err = fetchChanNumUpdates(openChanBucket, channel); err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read num updates: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2016-11-16 10:59:55 +03:00
|
|
|
if err = fetchChanAmountsTransferred(openChanBucket, channel); err != nil {
|
2017-02-08 03:41:14 +03:00
|
|
|
return nil, fmt.Errorf("unable to read sat transferred: %v", err)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
2017-01-23 10:31:01 +03:00
|
|
|
if err = fetchChanIsPending(openChanBucket, channel); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-06-06 01:02:27 +03:00
|
|
|
if err := fetchChanConfInfo(openChanBucket, channel); err != nil {
|
2017-05-11 02:44:40 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-05-01 08:53:54 +03:00
|
|
|
if err = fetchChanCommitFee(openChanBucket, channel); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-12-26 03:00:44 +03:00
|
|
|
|
|
|
|
return channel, nil
|
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
func deleteOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
|
2017-02-08 03:27:53 +03:00
|
|
|
channelID []byte, o *wire.OutPoint) error {
|
2016-06-23 02:15:07 +03:00
|
|
|
|
|
|
|
// First we'll delete all the "common" top level items stored outside
|
|
|
|
// the node's channel bucket.
|
|
|
|
if err := deleteChanCapacity(openChanBucket, channelID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := deleteChanMinFeePerKw(openChanBucket, channelID); err != nil {
|
2016-06-23 02:15:07 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := deleteChanNumUpdates(openChanBucket, channelID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-11-16 10:59:55 +03:00
|
|
|
if err := deleteChanAmountsTransferred(openChanBucket, channelID); err != nil {
|
2016-06-23 02:15:07 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-01-23 10:31:01 +03:00
|
|
|
if err := deleteChanIsPending(openChanBucket, channelID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-06-06 01:02:27 +03:00
|
|
|
if err := deleteChanConfInfo(openChanBucket, channelID); err != nil {
|
2017-05-11 02:44:40 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-05-01 08:53:54 +03:00
|
|
|
if err := deleteChanCommitFee(openChanBucket, channelID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-06-23 02:15:07 +03:00
|
|
|
|
|
|
|
// Finally, delete all the fields directly within the node's channel
|
|
|
|
// bucket.
|
|
|
|
if err := deleteChannelIDs(nodeChanBucket, channelID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := deleteChanConfigs(nodeChanBucket, channelID); err != nil {
|
2016-06-23 02:15:07 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := deleteChanCommitTxns(nodeChanBucket, channelID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := deleteChanFundingInfo(nodeChanBucket, channelID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := deleteChanRevocationState(nodeChanBucket, channelID); err != nil {
|
2016-06-23 02:15:07 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-02-08 03:27:53 +03:00
|
|
|
if err := deleteCurrentHtlcs(nodeChanBucket, o); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-06-23 02:15:07 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
func putChanCapacity(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
// Some scratch bytes re-used for serializing each of the uint64's.
|
|
|
|
scratch1 := make([]byte, 8)
|
|
|
|
scratch2 := make([]byte, 8)
|
|
|
|
scratch3 := make([]byte, 8)
|
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
copy(keyPrefix[:3], chanCapacityPrefix)
|
|
|
|
byteOrder.PutUint64(scratch1, uint64(channel.Capacity))
|
|
|
|
if err := openChanBucket.Put(keyPrefix, scratch1); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
copy(keyPrefix[:3], selfBalancePrefix)
|
2017-07-29 20:58:39 +03:00
|
|
|
byteOrder.PutUint64(scratch2, uint64(channel.LocalBalance))
|
2016-03-24 08:39:52 +03:00
|
|
|
if err := openChanBucket.Put(keyPrefix, scratch2); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
copy(keyPrefix[:3], theirBalancePrefix)
|
2017-07-29 20:58:39 +03:00
|
|
|
byteOrder.PutUint64(scratch3, uint64(channel.RemoteBalance))
|
2016-03-24 08:39:52 +03:00
|
|
|
return openChanBucket.Put(keyPrefix, scratch3)
|
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
func deleteChanCapacity(openChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
keyPrefix := make([]byte, 3+len(chanID))
|
|
|
|
copy(keyPrefix[3:], chanID)
|
|
|
|
|
|
|
|
copy(keyPrefix[:3], chanCapacityPrefix)
|
|
|
|
if err := openChanBucket.Delete(keyPrefix); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
copy(keyPrefix[:3], selfBalancePrefix)
|
|
|
|
if err := openChanBucket.Delete(keyPrefix); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
copy(keyPrefix[:3], theirBalancePrefix)
|
|
|
|
return openChanBucket.Delete(keyPrefix)
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
func fetchChanCapacity(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
// A byte slice re-used to compute each key prefix below.
|
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
copy(keyPrefix[:3], chanCapacityPrefix)
|
|
|
|
capacityBytes := openChanBucket.Get(keyPrefix)
|
|
|
|
channel.Capacity = btcutil.Amount(byteOrder.Uint64(capacityBytes))
|
|
|
|
|
|
|
|
copy(keyPrefix[:3], selfBalancePrefix)
|
|
|
|
selfBalanceBytes := openChanBucket.Get(keyPrefix)
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.LocalBalance = btcutil.Amount(byteOrder.Uint64(selfBalanceBytes))
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
copy(keyPrefix[:3], theirBalancePrefix)
|
|
|
|
theirBalanceBytes := openChanBucket.Get(keyPrefix)
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.RemoteBalance = btcutil.Amount(byteOrder.Uint64(theirBalanceBytes))
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-05-17 04:43:56 +03:00
|
|
|
func putChanFeePerKw(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-03-24 08:39:52 +03:00
|
|
|
scratch := make([]byte, 8)
|
2017-05-17 04:43:56 +03:00
|
|
|
byteOrder.PutUint64(scratch, uint64(channel.FeePerKw))
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
2017-07-29 20:58:39 +03:00
|
|
|
copy(keyPrefix, minFeePerKwPrefix)
|
2016-12-06 17:03:14 +03:00
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
|
|
|
|
|
|
|
return openChanBucket.Put(keyPrefix, scratch)
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
func deleteChanMinFeePerKw(openChanBucket *bolt.Bucket, chanID []byte) error {
|
2016-06-23 02:15:07 +03:00
|
|
|
keyPrefix := make([]byte, 3+len(chanID))
|
2017-07-29 20:58:39 +03:00
|
|
|
copy(keyPrefix, minFeePerKwPrefix)
|
2016-06-23 02:15:07 +03:00
|
|
|
copy(keyPrefix[3:], chanID)
|
|
|
|
return openChanBucket.Delete(keyPrefix)
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
func fetchChanMinFeePerKw(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
2017-07-29 20:58:39 +03:00
|
|
|
copy(keyPrefix, minFeePerKwPrefix)
|
2016-06-21 07:39:50 +03:00
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
feeBytes := openChanBucket.Get(keyPrefix)
|
2017-05-17 04:43:56 +03:00
|
|
|
channel.FeePerKw = btcutil.Amount(byteOrder.Uint64(feeBytes))
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func putChanNumUpdates(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
scratch := make([]byte, 8)
|
|
|
|
byteOrder.PutUint64(scratch, channel.NumUpdates)
|
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
2016-03-24 08:39:52 +03:00
|
|
|
copy(keyPrefix, updatePrefix)
|
2016-06-21 07:39:50 +03:00
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
return openChanBucket.Put(keyPrefix, scratch)
|
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
func deleteChanNumUpdates(openChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
keyPrefix := make([]byte, 3+len(chanID))
|
|
|
|
copy(keyPrefix, updatePrefix)
|
|
|
|
copy(keyPrefix[3:], chanID)
|
|
|
|
return openChanBucket.Delete(keyPrefix)
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
func fetchChanNumUpdates(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
2016-03-24 08:39:52 +03:00
|
|
|
copy(keyPrefix, updatePrefix)
|
2016-06-21 07:39:50 +03:00
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
updateBytes := openChanBucket.Get(keyPrefix)
|
|
|
|
channel.NumUpdates = byteOrder.Uint64(updateBytes)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-11-16 10:59:55 +03:00
|
|
|
func putChanAmountsTransferred(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-03-24 08:39:52 +03:00
|
|
|
scratch1 := make([]byte, 8)
|
|
|
|
scratch2 := make([]byte, 8)
|
2016-06-21 07:39:50 +03:00
|
|
|
|
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
copy(keyPrefix[:3], satSentPrefix)
|
2017-02-23 22:07:01 +03:00
|
|
|
byteOrder.PutUint64(scratch1, channel.TotalSatoshisSent)
|
2016-03-24 08:39:52 +03:00
|
|
|
if err := openChanBucket.Put(keyPrefix, scratch1); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2016-11-16 10:59:55 +03:00
|
|
|
copy(keyPrefix[:3], satReceivedPrefix)
|
2017-02-23 22:07:01 +03:00
|
|
|
byteOrder.PutUint64(scratch2, channel.TotalSatoshisReceived)
|
2016-03-24 08:39:52 +03:00
|
|
|
return openChanBucket.Put(keyPrefix, scratch2)
|
|
|
|
}
|
|
|
|
|
2016-11-16 10:59:55 +03:00
|
|
|
func deleteChanAmountsTransferred(openChanBucket *bolt.Bucket, chanID []byte) error {
|
2016-06-23 02:15:07 +03:00
|
|
|
keyPrefix := make([]byte, 3+len(chanID))
|
|
|
|
copy(keyPrefix[3:], chanID)
|
|
|
|
|
|
|
|
copy(keyPrefix[:3], satSentPrefix)
|
|
|
|
if err := openChanBucket.Delete(keyPrefix); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-11-16 10:59:55 +03:00
|
|
|
copy(keyPrefix[:3], satReceivedPrefix)
|
2016-06-23 02:15:07 +03:00
|
|
|
return openChanBucket.Delete(keyPrefix)
|
|
|
|
}
|
|
|
|
|
2016-11-16 10:59:55 +03:00
|
|
|
func fetchChanAmountsTransferred(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
|
|
|
copy(keyPrefix[:3], satSentPrefix)
|
|
|
|
totalSentBytes := openChanBucket.Get(keyPrefix)
|
|
|
|
channel.TotalSatoshisSent = byteOrder.Uint64(totalSentBytes)
|
|
|
|
|
2016-11-16 10:59:55 +03:00
|
|
|
copy(keyPrefix[:3], satReceivedPrefix)
|
2016-03-24 08:39:52 +03:00
|
|
|
totalReceivedBytes := openChanBucket.Get(keyPrefix)
|
|
|
|
channel.TotalSatoshisReceived = byteOrder.Uint64(totalReceivedBytes)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-01-23 10:31:01 +03:00
|
|
|
func putChanIsPending(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
scratch := make([]byte, 2)
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2017-01-23 10:31:01 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
|
|
|
copy(keyPrefix[:3], isPendingPrefix)
|
|
|
|
|
|
|
|
if channel.IsPending {
|
|
|
|
byteOrder.PutUint16(scratch, uint16(1))
|
|
|
|
return openChanBucket.Put(keyPrefix, scratch)
|
|
|
|
}
|
|
|
|
|
|
|
|
byteOrder.PutUint16(scratch, uint16(0))
|
|
|
|
return openChanBucket.Put(keyPrefix, scratch)
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteChanIsPending(openChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
keyPrefix := make([]byte, 3+len(chanID))
|
|
|
|
copy(keyPrefix[3:], chanID)
|
|
|
|
copy(keyPrefix[:3], isPendingPrefix)
|
|
|
|
return openChanBucket.Delete(keyPrefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchChanIsPending(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2017-01-23 10:31:01 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
|
|
|
copy(keyPrefix[:3], isPendingPrefix)
|
|
|
|
|
|
|
|
isPending := byteOrder.Uint16(openChanBucket.Get(keyPrefix))
|
|
|
|
if isPending == 1 {
|
|
|
|
channel.IsPending = true
|
|
|
|
} else {
|
|
|
|
channel.IsPending = false
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
func putChanConfInfo(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2017-05-11 02:44:40 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2017-05-11 02:44:40 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
keyPrefix := make([]byte, len(confInfoPrefix)+b.Len())
|
|
|
|
copy(keyPrefix[:len(confInfoPrefix)], confInfoPrefix)
|
|
|
|
copy(keyPrefix[len(confInfoPrefix):], b.Bytes())
|
|
|
|
|
|
|
|
// We store the conf info in the following format: broadcast || open.
|
2017-06-16 23:28:26 +03:00
|
|
|
var scratch [12]byte
|
2017-06-06 01:02:27 +03:00
|
|
|
byteOrder.PutUint32(scratch[:], channel.FundingBroadcastHeight)
|
2017-06-16 23:28:26 +03:00
|
|
|
byteOrder.PutUint64(scratch[4:], channel.ShortChanID.ToUint64())
|
2017-05-11 02:44:40 +03:00
|
|
|
|
|
|
|
return openChanBucket.Put(keyPrefix, scratch[:])
|
|
|
|
}
|
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
func fetchChanConfInfo(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2017-05-11 02:44:40 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2017-05-11 02:44:40 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
keyPrefix := make([]byte, len(confInfoPrefix)+b.Len())
|
|
|
|
copy(keyPrefix[:len(confInfoPrefix)], confInfoPrefix)
|
|
|
|
copy(keyPrefix[len(confInfoPrefix):], b.Bytes())
|
2017-05-11 02:44:40 +03:00
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
confInfoBytes := openChanBucket.Get(keyPrefix)
|
|
|
|
channel.FundingBroadcastHeight = byteOrder.Uint32(confInfoBytes[:4])
|
2017-06-16 23:28:26 +03:00
|
|
|
channel.ShortChanID = lnwire.NewShortChanIDFromInt(
|
|
|
|
byteOrder.Uint64(confInfoBytes[4:]),
|
|
|
|
)
|
2017-05-11 02:44:40 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-06-06 01:02:27 +03:00
|
|
|
func deleteChanConfInfo(openChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
keyPrefix := make([]byte, len(confInfoPrefix)+len(chanID))
|
|
|
|
copy(keyPrefix[:len(confInfoPrefix)], confInfoPrefix)
|
|
|
|
copy(keyPrefix[len(confInfoPrefix):], chanID)
|
2017-05-11 02:44:40 +03:00
|
|
|
return openChanBucket.Delete(keyPrefix)
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
func putChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-11-16 05:47:05 +03:00
|
|
|
// TODO(roasbeef): just pass in chanID everywhere for puts
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct the id key: cid || channelID.
|
|
|
|
// TODO(roasbeef): abstract out to func
|
|
|
|
idKey := make([]byte, len(chanIDKey)+b.Len())
|
|
|
|
copy(idKey[:3], chanIDKey)
|
|
|
|
copy(idKey[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2016-10-26 02:11:23 +03:00
|
|
|
idBytes := channel.IdentityPub.SerializeCompressed()
|
|
|
|
return nodeChanBucket.Put(idKey, idBytes)
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
func deleteChannelIDs(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
idKey := make([]byte, len(chanIDKey)+len(chanID))
|
|
|
|
copy(idKey[:3], chanIDKey)
|
|
|
|
copy(idKey[3:], chanID)
|
|
|
|
return nodeChanBucket.Delete(idKey)
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
func fetchChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-10-26 02:11:23 +03:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
b bytes.Buffer
|
|
|
|
)
|
|
|
|
|
2017-07-29 05:40:52 +03:00
|
|
|
if err = writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct the id key: cid || channelID.
|
|
|
|
idKey := make([]byte, len(chanIDKey)+b.Len())
|
|
|
|
copy(idKey[:3], chanIDKey)
|
|
|
|
copy(idKey[3:], b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
idBytes := nodeChanBucket.Get(idKey)
|
2016-10-26 02:11:23 +03:00
|
|
|
channel.IdentityPub, err = btcec.ParsePubKey(idBytes, btcec.S256())
|
2017-07-29 20:58:39 +03:00
|
|
|
if err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
return nil
|
2016-06-23 02:15:07 +03:00
|
|
|
}
|
|
|
|
|
2017-05-01 08:53:54 +03:00
|
|
|
func putChanCommitFee(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
scratch := make([]byte, 8)
|
|
|
|
byteOrder.PutUint64(scratch, uint64(channel.CommitFee))
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2017-05-01 08:53:54 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix, commitFeePrefix)
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
|
|
|
|
|
|
|
return openChanBucket.Put(keyPrefix, scratch)
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchChanCommitFee(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2017-05-01 08:53:54 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
keyPrefix := make([]byte, 3+b.Len())
|
|
|
|
copy(keyPrefix, commitFeePrefix)
|
|
|
|
copy(keyPrefix[3:], b.Bytes())
|
|
|
|
|
|
|
|
commitFeeBytes := openChanBucket.Get(keyPrefix)
|
|
|
|
channel.CommitFee = btcutil.Amount(byteOrder.Uint64(commitFeeBytes))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteChanCommitFee(openChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
commitFeeKey := make([]byte, 3+len(chanID))
|
|
|
|
copy(commitFeeKey, commitFeePrefix)
|
|
|
|
copy(commitFeeKey[3:], chanID)
|
|
|
|
|
|
|
|
return openChanBucket.Delete(commitFeeKey)
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
func putChanCommitTxns(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var bc bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&bc, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
txnsKey := make([]byte, len(commitTxnsKey)+bc.Len())
|
|
|
|
copy(txnsKey[:3], commitTxnsKey)
|
|
|
|
copy(txnsKey[3:], bc.Bytes())
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
var b bytes.Buffer
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := channel.CommitTx.Serialize(&b); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
if err := wire.WriteVarBytes(&b, 0, channel.CommitSig); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
return nodeChanBucket.Put(txnsKey, b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
func deleteChanCommitTxns(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
txnsKey := make([]byte, len(commitTxnsKey)+len(chanID))
|
|
|
|
copy(txnsKey[:3], commitTxnsKey)
|
|
|
|
copy(txnsKey[3:], chanID)
|
|
|
|
return nodeChanBucket.Delete(txnsKey)
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
func fetchChanCommitTxns(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var bc bytes.Buffer
|
2016-07-06 02:44:39 +03:00
|
|
|
var err error
|
2017-07-29 05:40:52 +03:00
|
|
|
if err = writeOutpoint(&bc, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
txnsKey := make([]byte, len(commitTxnsKey)+bc.Len())
|
|
|
|
copy(txnsKey[:3], commitTxnsKey)
|
|
|
|
copy(txnsKey[3:], bc.Bytes())
|
|
|
|
|
|
|
|
txnBytes := bytes.NewReader(nodeChanBucket.Get(txnsKey))
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.CommitTx = *wire.NewMsgTx(2)
|
|
|
|
if err = channel.CommitTx.Deserialize(txnBytes); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.CommitSig, err = wire.ReadVarBytes(txnBytes, 0, 80, "")
|
2016-07-06 02:44:39 +03:00
|
|
|
if err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
return nil
|
|
|
|
}
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
func putChanConfigs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
var b bytes.Buffer
|
|
|
|
|
|
|
|
putChanConfig := func(cfg *ChannelConfig) error {
|
|
|
|
err := binary.Write(&b, byteOrder, cfg.DustLimit)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = binary.Write(&b, byteOrder, cfg.MaxPendingAmount)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = binary.Write(&b, byteOrder, cfg.ChanReserve)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = binary.Write(&b, byteOrder, cfg.MinHTLC)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = binary.Write(&b, byteOrder, cfg.CsvDelay)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = binary.Write(&b, byteOrder, cfg.MaxAcceptedHtlcs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = b.Write(cfg.MultiSigKey.SerializeCompressed())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = b.Write(cfg.RevocationBasePoint.SerializeCompressed())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = b.Write(cfg.PaymentBasePoint.SerializeCompressed())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = b.Write(cfg.DelayBasePoint.SerializeCompressed())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2015-12-26 02:00:20 +03:00
|
|
|
}
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
putChanConfig(&channel.LocalChanCfg)
|
|
|
|
putChanConfig(&channel.RemoteChanCfg)
|
|
|
|
|
|
|
|
var bc bytes.Buffer
|
|
|
|
if err := writeOutpoint(&bc, &channel.FundingOutpoint); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
configKey := make([]byte, len(chanConfigPrefix)+len(bc.Bytes()))
|
|
|
|
copy(configKey, chanConfigPrefix)
|
|
|
|
copy(configKey, bc.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
return nodeChanBucket.Put(configKey, b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
func fetchChanConfigs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var bc bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&bc, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
configKey := make([]byte, len(chanConfigPrefix)+len(bc.Bytes()))
|
|
|
|
copy(configKey, chanConfigPrefix)
|
|
|
|
copy(configKey, bc.Bytes())
|
2016-06-21 07:39:50 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
configBytes := nodeChanBucket.Get(configKey)
|
|
|
|
if configBytes == nil {
|
|
|
|
return fmt.Errorf("unable to find channel config for %v: ",
|
|
|
|
channel.FundingOutpoint)
|
2015-12-26 02:00:20 +03:00
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
configReader := bytes.NewReader(configBytes)
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
fetchChanConfig := func() (*ChannelConfig, error) {
|
|
|
|
cfg := &ChannelConfig{}
|
|
|
|
|
|
|
|
err := binary.Read(configReader, byteOrder, &cfg.DustLimit)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = binary.Read(configReader, byteOrder, &cfg.MaxPendingAmount)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = binary.Read(configReader, byteOrder, &cfg.ChanReserve)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = binary.Read(configReader, byteOrder, &cfg.MinHTLC)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = binary.Read(configReader, byteOrder, &cfg.CsvDelay)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = binary.Read(configReader, byteOrder, &cfg.MaxAcceptedHtlcs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var pub [33]byte
|
|
|
|
readKey := func() (*btcec.PublicKey, error) {
|
|
|
|
if _, err := io.ReadFull(configReader, pub[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return btcec.ParsePubKey(pub[:], btcec.S256())
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg.MultiSigKey, err = readKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cfg.RevocationBasePoint, err = readKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cfg.PaymentBasePoint, err = readKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cfg.DelayBasePoint, err = readKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return cfg, nil
|
2015-12-26 02:00:20 +03:00
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
|
|
|
|
var err error
|
|
|
|
cfg, err := fetchChanConfig()
|
|
|
|
if err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.LocalChanCfg = *cfg
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
cfg, err = fetchChanConfig()
|
|
|
|
if err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.RemoteChanCfg = *cfg
|
2015-12-26 02:00:20 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteChanConfigs(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
configKey := make([]byte, len(chanConfigPrefix)+len(chanID))
|
|
|
|
copy(configKey, chanConfigPrefix)
|
|
|
|
copy(configKey, chanID)
|
|
|
|
return nodeChanBucket.Delete(configKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
func putChanFundingInfo(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|
|
|
var bc bytes.Buffer
|
|
|
|
if err := writeOutpoint(&bc, &channel.FundingOutpoint); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
fundTxnKey := make([]byte, len(fundingTxnKey)+bc.Len())
|
|
|
|
copy(fundTxnKey[:3], fundingTxnKey)
|
|
|
|
copy(fundTxnKey[3:], bc.Bytes())
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
2015-12-26 02:00:20 +03:00
|
|
|
|
2016-11-16 05:50:24 +03:00
|
|
|
var boolByte [1]byte
|
|
|
|
if channel.IsInitiator {
|
|
|
|
boolByte[0] = 1
|
|
|
|
} else {
|
|
|
|
boolByte[0] = 0
|
|
|
|
}
|
|
|
|
if _, err := b.Write(boolByte[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
// TODO(roasbeef): make first field instead?
|
2016-11-16 04:41:22 +03:00
|
|
|
if _, err := b.Write([]byte{uint8(channel.ChanType)}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
if _, err := b.Write(channel.ChainHash[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-11-16 04:41:22 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
var scratch [2]byte
|
|
|
|
byteOrder.PutUint16(scratch[:], channel.NumConfsRequired)
|
|
|
|
if _, err := b.Write(scratch[:]); err != nil {
|
2017-01-24 04:15:14 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
return nodeChanBucket.Put(fundTxnKey, b.Bytes())
|
2015-12-26 02:00:20 +03:00
|
|
|
}
|
|
|
|
|
2016-06-23 02:15:07 +03:00
|
|
|
func deleteChanFundingInfo(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
fundTxnKey := make([]byte, len(fundingTxnKey)+len(chanID))
|
|
|
|
copy(fundTxnKey[:3], fundingTxnKey)
|
|
|
|
copy(fundTxnKey[3:], chanID)
|
|
|
|
return nodeChanBucket.Delete(fundTxnKey)
|
|
|
|
}
|
|
|
|
|
2016-08-13 00:57:27 +03:00
|
|
|
func fetchChanFundingInfo(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
fundTxnKey := make([]byte, len(fundingTxnKey)+b.Len())
|
|
|
|
copy(fundTxnKey[:3], fundingTxnKey)
|
|
|
|
copy(fundTxnKey[3:], b.Bytes())
|
|
|
|
|
|
|
|
infoBytes := bytes.NewReader(nodeChanBucket.Get(fundTxnKey))
|
2015-12-26 02:00:20 +03:00
|
|
|
|
2016-11-16 05:50:24 +03:00
|
|
|
var boolByte [1]byte
|
|
|
|
if _, err := io.ReadFull(infoBytes, boolByte[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if boolByte[0] == 1 {
|
|
|
|
channel.IsInitiator = true
|
|
|
|
} else {
|
|
|
|
channel.IsInitiator = false
|
|
|
|
}
|
|
|
|
|
2016-11-16 04:41:22 +03:00
|
|
|
var chanType [1]byte
|
|
|
|
if _, err := io.ReadFull(infoBytes, chanType[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
channel.ChanType = ChannelType(chanType[0])
|
2017-07-29 20:58:39 +03:00
|
|
|
if _, err := io.ReadFull(infoBytes, channel.ChainHash[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-11-16 04:41:22 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
var scratch [2]byte
|
|
|
|
if _, err := infoBytes.Read(scratch[:]); err != nil {
|
2017-01-24 04:15:14 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.NumConfsRequired = byteOrder.Uint16(scratch[:])
|
2017-01-24 04:15:14 +03:00
|
|
|
|
2016-03-24 08:39:52 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
func putChanRevocationState(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-03-24 08:39:52 +03:00
|
|
|
var b bytes.Buffer
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
curRevKey := channel.RemoteCurrentRevocation.SerializeCompressed()
|
|
|
|
if err := wire.WriteVarBytes(&b, 0, curRevKey); err != nil {
|
2016-07-06 02:48:23 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-06-30 21:39:57 +03:00
|
|
|
// TODO(roasbeef): shouldn't be storing on disk, should re-derive as
|
|
|
|
// needed
|
2017-02-24 22:53:49 +03:00
|
|
|
if err := channel.RevocationProducer.Encode(&b); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-02-24 22:53:49 +03:00
|
|
|
if err := channel.RevocationStore.Encode(&b); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
var bc bytes.Buffer
|
|
|
|
if err := writeOutpoint(&bc, &channel.FundingOutpoint); err != nil {
|
2016-11-16 05:51:48 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 21:24:03 +03:00
|
|
|
// We place the next revocation key at the very end, as under certain
|
|
|
|
// circumstances (when a channel is initially funded), this value will
|
|
|
|
// not yet have been set.
|
|
|
|
//
|
|
|
|
// TODO(roasbeef): segment the storage?
|
|
|
|
if channel.RemoteNextRevocation != nil {
|
|
|
|
nextRevKey := channel.RemoteNextRevocation.SerializeCompressed()
|
|
|
|
if err := wire.WriteVarBytes(&b, 0, nextRevKey); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-12-14 17:01:48 +03:00
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
revocationKey := make([]byte, len(revocationStateKey)+bc.Len())
|
|
|
|
copy(revocationKey[:3], revocationStateKey)
|
|
|
|
copy(revocationKey[3:], bc.Bytes())
|
|
|
|
return nodeChanBucket.Put(revocationKey, b.Bytes())
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
func deleteChanRevocationState(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
|
|
|
revocationKey := make([]byte, len(revocationStateKey)+len(chanID))
|
|
|
|
copy(revocationKey[:3], revocationStateKey)
|
|
|
|
copy(revocationKey[3:], chanID)
|
|
|
|
return nodeChanBucket.Delete(revocationKey)
|
2016-06-23 02:15:07 +03:00
|
|
|
}
|
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
func fetchChanRevocationState(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
2016-06-21 07:39:50 +03:00
|
|
|
var b bytes.Buffer
|
2017-07-29 05:40:52 +03:00
|
|
|
if err := writeOutpoint(&b, &channel.FundingOutpoint); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
preimageKey := make([]byte, len(revocationStateKey)+b.Len())
|
|
|
|
copy(preimageKey[:3], revocationStateKey)
|
2016-12-14 17:01:48 +03:00
|
|
|
copy(preimageKey[3:], b.Bytes())
|
2016-06-21 07:39:50 +03:00
|
|
|
|
2016-12-14 17:01:48 +03:00
|
|
|
reader := bytes.NewReader(nodeChanBucket.Get(preimageKey))
|
2016-03-24 08:39:52 +03:00
|
|
|
|
2017-07-29 20:58:39 +03:00
|
|
|
curRevKeyBytes, err := wire.ReadVarBytes(reader, 0, 1000, "")
|
2016-06-30 21:39:57 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-07-29 20:58:39 +03:00
|
|
|
channel.RemoteCurrentRevocation, err = btcec.ParsePubKey(curRevKeyBytes, btcec.S256())
|
2016-06-30 21:39:57 +03:00
|
|
|
if err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-06-30 21:39:57 +03:00
|
|
|
// TODO(roasbeef): should be rederiving on fly, or encrypting on disk.
|
2017-02-24 22:53:49 +03:00
|
|
|
var root [32]byte
|
|
|
|
if _, err := io.ReadFull(reader, root[:]); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-02-24 22:53:49 +03:00
|
|
|
channel.RevocationProducer, err = shachain.NewRevocationProducerFromBytes(root[:])
|
2015-12-26 02:00:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-02-24 22:53:49 +03:00
|
|
|
channel.RevocationStore, err = shachain.NewRevocationStoreFromBytes(reader)
|
2015-12-26 02:00:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 21:24:03 +03:00
|
|
|
// We'll attempt to see if the remote party's next revocation key is
|
|
|
|
// currently set, if so then we'll read and deserialize it. Otherwise,
|
|
|
|
// we can exit early.
|
|
|
|
if reader.Len() != 0 {
|
|
|
|
nextRevKeyBytes, err := wire.ReadVarBytes(reader, 0, 1000, "")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
channel.RemoteNextRevocation, err = btcec.ParsePubKey(
|
|
|
|
nextRevKeyBytes, btcec.S256(),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2016-03-24 08:39:52 +03:00
|
|
|
}
|
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
func serializeHTLC(w io.Writer, h *HTLC) error {
|
|
|
|
if err := wire.WriteVarBytes(w, 0, h.Signature); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
if _, err := w.Write(h.RHash[:]); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
|
|
|
|
if err := binary.Write(w, byteOrder, h.Amt); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
if err := binary.Write(w, byteOrder, h.RefundTimeout); err != nil {
|
2016-06-21 07:39:50 +03:00
|
|
|
return err
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
if err := binary.Write(w, byteOrder, h.OutputIndex); err != nil {
|
2015-12-26 02:00:20 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-09-03 04:51:34 +03:00
|
|
|
|
|
|
|
var boolByte [1]byte
|
|
|
|
if h.Incoming {
|
|
|
|
boolByte[0] = 1
|
|
|
|
} else {
|
|
|
|
boolByte[0] = 0
|
|
|
|
}
|
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
if _, err := w.Write(boolByte[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-09-03 04:51:34 +03:00
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
return nil
|
2016-09-03 04:51:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func deserializeHTLC(r io.Reader) (*HTLC, error) {
|
|
|
|
h := &HTLC{}
|
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
sigBytes, err := wire.ReadVarBytes(r, 0, 80, "")
|
|
|
|
if err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
h.Signature = sigBytes
|
2016-09-03 04:51:34 +03:00
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
if _, err := io.ReadFull(r, h.RHash[:]); err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
if err := binary.Read(r, byteOrder, &h.Amt); err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
if err := binary.Read(r, byteOrder, &h.RefundTimeout); err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
if err := binary.Read(r, byteOrder, &h.OutputIndex); err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-07-29 21:18:12 +03:00
|
|
|
var scratch [1]byte
|
|
|
|
if _, err := r.Read(scratch[:]); err != nil {
|
2016-11-18 05:28:07 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
|
|
|
|
if scratch[0] == 1 {
|
|
|
|
h.Incoming = true
|
|
|
|
} else {
|
|
|
|
h.Incoming = false
|
|
|
|
}
|
2016-11-18 05:28:07 +03:00
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
return h, nil
|
|
|
|
}
|
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
func makeHtlcKey(o *wire.OutPoint) [39]byte {
|
|
|
|
var (
|
|
|
|
n int
|
|
|
|
k [39]byte
|
|
|
|
)
|
|
|
|
|
|
|
|
// chk || txid || index
|
|
|
|
n += copy(k[:], currentHtlcKey)
|
|
|
|
n += copy(k[n:], o.Hash[:])
|
|
|
|
var scratch [4]byte
|
|
|
|
byteOrder.PutUint32(scratch[:], o.Index)
|
|
|
|
copy(k[n:], scratch[:])
|
|
|
|
|
|
|
|
return k
|
|
|
|
}
|
|
|
|
|
|
|
|
func putCurrentHtlcs(nodeChanBucket *bolt.Bucket, htlcs []*HTLC,
|
|
|
|
o *wire.OutPoint) error {
|
|
|
|
var b bytes.Buffer
|
|
|
|
|
|
|
|
for _, htlc := range htlcs {
|
|
|
|
if err := serializeHTLC(&b, htlc); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
htlcKey := makeHtlcKey(o)
|
|
|
|
return nodeChanBucket.Put(htlcKey[:], b.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchCurrentHtlcs(nodeChanBucket *bolt.Bucket,
|
|
|
|
o *wire.OutPoint) ([]*HTLC, error) {
|
|
|
|
|
|
|
|
htlcKey := makeHtlcKey(o)
|
|
|
|
htlcBytes := nodeChanBucket.Get(htlcKey[:])
|
|
|
|
if htlcBytes == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(roasbeef): can preallocate here
|
|
|
|
var htlcs []*HTLC
|
|
|
|
htlcReader := bytes.NewReader(htlcBytes)
|
|
|
|
for htlcReader.Len() != 0 {
|
|
|
|
htlc, err := deserializeHTLC(htlcReader)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
htlcs = append(htlcs, htlc)
|
|
|
|
}
|
|
|
|
|
|
|
|
return htlcs, nil
|
|
|
|
}
|
|
|
|
|
2017-02-08 03:27:53 +03:00
|
|
|
func deleteCurrentHtlcs(nodeChanBucket *bolt.Bucket, o *wire.OutPoint) error {
|
|
|
|
htlcKey := makeHtlcKey(o)
|
|
|
|
return nodeChanBucket.Delete(htlcKey[:])
|
|
|
|
}
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
func serializeChannelDelta(w io.Writer, delta *ChannelDelta) error {
|
|
|
|
// TODO(roasbeef): could use compression here to reduce on-disk space.
|
|
|
|
var scratch [8]byte
|
|
|
|
byteOrder.PutUint64(scratch[:], uint64(delta.LocalBalance))
|
|
|
|
if _, err := w.Write(scratch[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
byteOrder.PutUint64(scratch[:], uint64(delta.RemoteBalance))
|
|
|
|
if _, err := w.Write(scratch[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-02-16 16:03:24 +03:00
|
|
|
byteOrder.PutUint64(scratch[:], delta.UpdateNum)
|
|
|
|
if _, err := w.Write(scratch[:]); err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
numHtlcs := uint64(len(delta.Htlcs))
|
|
|
|
if err := wire.WriteVarInt(w, 0, numHtlcs); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, htlc := range delta.Htlcs {
|
|
|
|
if err := serializeHTLC(w, htlc); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-01 08:53:54 +03:00
|
|
|
byteOrder.PutUint64(scratch[:], uint64(delta.CommitFee))
|
|
|
|
if _, err := w.Write(scratch[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-14 21:38:35 +03:00
|
|
|
byteOrder.PutUint64(scratch[:], uint64(delta.FeePerKw))
|
|
|
|
if _, err := w.Write(scratch[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func deserializeChannelDelta(r io.Reader) (*ChannelDelta, error) {
|
|
|
|
var (
|
|
|
|
err error
|
|
|
|
scratch [8]byte
|
|
|
|
)
|
|
|
|
|
|
|
|
delta := &ChannelDelta{}
|
|
|
|
|
|
|
|
if _, err := r.Read(scratch[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
delta.LocalBalance = btcutil.Amount(byteOrder.Uint64(scratch[:]))
|
|
|
|
if _, err := r.Read(scratch[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
delta.RemoteBalance = btcutil.Amount(byteOrder.Uint64(scratch[:]))
|
|
|
|
|
2017-02-16 16:03:24 +03:00
|
|
|
if _, err := r.Read(scratch[:]); err != nil {
|
2016-09-03 04:51:34 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-02-16 16:03:24 +03:00
|
|
|
delta.UpdateNum = byteOrder.Uint64(scratch[:])
|
2016-09-03 04:51:34 +03:00
|
|
|
|
|
|
|
numHtlcs, err := wire.ReadVarInt(r, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
delta.Htlcs = make([]*HTLC, numHtlcs)
|
|
|
|
for i := uint64(0); i < numHtlcs; i++ {
|
|
|
|
htlc, err := deserializeHTLC(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
delta.Htlcs[i] = htlc
|
|
|
|
}
|
2017-05-01 08:53:54 +03:00
|
|
|
if _, err := r.Read(scratch[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
delta.CommitFee = btcutil.Amount(byteOrder.Uint64(scratch[:]))
|
2016-09-03 04:51:34 +03:00
|
|
|
|
2017-07-14 21:38:35 +03:00
|
|
|
if _, err := r.Read(scratch[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
delta.FeePerKw = btcutil.Amount(byteOrder.Uint64(scratch[:]))
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
return delta, nil
|
|
|
|
}
|
|
|
|
|
2017-02-21 08:58:34 +03:00
|
|
|
func makeLogKey(o *wire.OutPoint, updateNum uint64) [44]byte {
|
2016-09-07 05:17:34 +03:00
|
|
|
var (
|
2017-02-16 16:03:24 +03:00
|
|
|
scratch [8]byte
|
2016-09-07 05:17:34 +03:00
|
|
|
n int
|
2017-02-21 08:58:34 +03:00
|
|
|
|
|
|
|
// txid (32) || index (4) || update_num (8)
|
|
|
|
// 32 + 4 + 8 = 44
|
|
|
|
k [44]byte
|
2016-09-07 05:17:34 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
n += copy(k[:], o.Hash[:])
|
|
|
|
|
2017-02-16 16:03:24 +03:00
|
|
|
byteOrder.PutUint32(scratch[:4], o.Index)
|
2017-02-21 08:58:34 +03:00
|
|
|
n += copy(k[n:], scratch[:4])
|
2016-09-07 05:17:34 +03:00
|
|
|
|
2017-02-16 16:03:24 +03:00
|
|
|
byteOrder.PutUint64(scratch[:], updateNum)
|
2016-09-07 05:17:34 +03:00
|
|
|
copy(k[n:], scratch[:])
|
|
|
|
|
|
|
|
return k
|
|
|
|
}
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
func appendChannelLogEntry(log *bolt.Bucket, delta *ChannelDelta,
|
|
|
|
chanPoint *wire.OutPoint) error {
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
if err := serializeChannelDelta(&b, delta); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
logEntrykey := makeLogKey(chanPoint, delta.UpdateNum)
|
2016-09-03 04:51:34 +03:00
|
|
|
return log.Put(logEntrykey[:], b.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchChannelLogEntry(log *bolt.Bucket, chanPoint *wire.OutPoint,
|
2017-02-16 16:03:24 +03:00
|
|
|
updateNum uint64) (*ChannelDelta, error) {
|
2016-09-03 04:51:34 +03:00
|
|
|
|
2016-09-07 05:17:34 +03:00
|
|
|
logEntrykey := makeLogKey(chanPoint, updateNum)
|
2016-09-03 04:51:34 +03:00
|
|
|
deltaBytes := log.Get(logEntrykey[:])
|
|
|
|
if deltaBytes == nil {
|
|
|
|
return nil, fmt.Errorf("log entry not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
deltaReader := bytes.NewReader(deltaBytes)
|
|
|
|
|
|
|
|
return deserializeChannelDelta(deltaReader)
|
|
|
|
}
|
|
|
|
|
2017-02-08 03:27:53 +03:00
|
|
|
func wipeChannelLogEntries(log *bolt.Bucket, o *wire.OutPoint) error {
|
|
|
|
var (
|
|
|
|
n int
|
|
|
|
logPrefix [32 + 4]byte
|
|
|
|
scratch [4]byte
|
|
|
|
)
|
|
|
|
|
|
|
|
// First we'll construct a key prefix that we'll use to scan through
|
|
|
|
// and delete all the log entries related to this channel. The format
|
|
|
|
// for log entries within the database is: txid || index || update_num.
|
|
|
|
// We'll construct a prefix key with the first two thirds of the full
|
|
|
|
// key to scan with and delete all entries.
|
|
|
|
n += copy(logPrefix[:], o.Hash[:])
|
|
|
|
byteOrder.PutUint32(scratch[:], o.Index)
|
|
|
|
copy(logPrefix[n:], scratch[:])
|
|
|
|
|
|
|
|
// With the prefix constructed, scan through the log bucket from the
|
|
|
|
// starting point of the log entries for this channel. We'll keep
|
|
|
|
// deleting keys until the prefix no longer matches.
|
|
|
|
logCursor := log.Cursor()
|
|
|
|
for logKey, _ := logCursor.Seek(logPrefix[:]); bytes.HasPrefix(logKey, logPrefix[:]); logKey, _ = logCursor.Next() {
|
|
|
|
if err := log.Delete(logKey); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-06-21 07:39:50 +03:00
|
|
|
func writeOutpoint(w io.Writer, o *wire.OutPoint) error {
|
2016-09-03 04:51:34 +03:00
|
|
|
// TODO(roasbeef): make all scratch buffers on the stack
|
2016-06-21 07:39:50 +03:00
|
|
|
scratch := make([]byte, 4)
|
|
|
|
|
2016-09-03 04:51:34 +03:00
|
|
|
// TODO(roasbeef): write raw 32 bytes instead of wasting the extra
|
|
|
|
// byte.
|
2016-06-21 07:39:50 +03:00
|
|
|
if err := wire.WriteVarBytes(w, 0, o.Hash[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
byteOrder.PutUint32(scratch, o.Index)
|
2017-02-23 21:59:50 +03:00
|
|
|
_, err := w.Write(scratch)
|
|
|
|
return err
|
2016-06-21 07:39:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func readOutpoint(r io.Reader, o *wire.OutPoint) error {
|
|
|
|
scratch := make([]byte, 4)
|
|
|
|
|
|
|
|
txid, err := wire.ReadVarBytes(r, 0, 32, "prevout")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
copy(o.Hash[:], txid)
|
|
|
|
|
|
|
|
if _, err := r.Read(scratch); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
o.Index = byteOrder.Uint32(scratch)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2017-05-05 01:19:21 +03:00
|
|
|
|
|
|
|
func writeBool(w io.Writer, b bool) error {
|
|
|
|
boolByte := byte(0x01)
|
|
|
|
if !b {
|
|
|
|
boolByte = byte(0x00)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := w.Write([]byte{boolByte}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(roasbeef): make sweep to use this and above everywhere
|
|
|
|
// * using this because binary.Write can only handle bools post go1.8
|
|
|
|
func readBool(r io.Reader) (bool, error) {
|
|
|
|
var boolByte [1]byte
|
|
|
|
if _, err := io.ReadFull(r, boolByte[:]); err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if boolByte[0] == 0x00 {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|
2017-07-29 21:18:12 +03:00
|
|
|
|
|
|
|
// TODO(roasbeef): add readElement/writeElement funcs
|
|
|
|
// * after go1.9 can use binary.WriteBool etc?
|