Started working on state machine
* Added description in lnwire/README.md for state machine * Figured out mutex stuff... * Started the State Machine (using dummy functions for net/db) * Minor corrections in wire protocol (changed some names/types) - Renamed StagingID to HTLCKey of type HTLCKey (uint64)
This commit is contained in:
parent
0c304cbb2f
commit
1981001a29
5
lnstate/README.md
Normal file
5
lnstate/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
I'm using this as a temporary repo for the state machine.
|
||||||
|
|
||||||
|
All hooks into real stuff isn't used right now.
|
||||||
|
|
||||||
|
Will merge into lnwallet/channel.go later?
|
418
lnstate/lnstate.go
Normal file
418
lnstate/lnstate.go
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
package lnstate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
//"github.com/btcsuite/btcd/btcec"
|
||||||
|
//"atomic"
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/btcsuite/btcutil"
|
||||||
|
"li.lan/labs/plasma/channeldb"
|
||||||
|
"li.lan/labs/plasma/lnwire"
|
||||||
|
"li.lan/labs/plasma/shachain"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
//This is a state machine which allows for simultaneous high-volume
|
||||||
|
//bidirectional payments. The design goal is to for all steps to be
|
||||||
|
//non-blocking over-the-wire on signing/revoking with the counterparty.
|
||||||
|
//
|
||||||
|
//A *single* Lightning Network node on one reasonably high-speced computer
|
||||||
|
//should be able to conduct transactions at Visa-scale (one Lightning Network
|
||||||
|
//node can process thousands of transactions per second total), enabling
|
||||||
|
//incredible volume for the entire network. This state machine design should
|
||||||
|
//enable transaction volume for the entire network greater than current Visa
|
||||||
|
//card transaction load by many orders of magnitude.
|
||||||
|
//
|
||||||
|
//More info on the design is in lnwire/README.md
|
||||||
|
|
||||||
|
//NOTE: WORK IN PROGRESS
|
||||||
|
//TODO: Will make channel-friendly & add in mutex stuff
|
||||||
|
|
||||||
|
//DUMMY FunCTIONS FOR UPDATING LATER
|
||||||
|
func disk() {
|
||||||
|
}
|
||||||
|
func net(msg lnwire.Message) {
|
||||||
|
fmt.Println(msg)
|
||||||
|
}
|
||||||
|
func (l *LNChannel) sendErrorPkt() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//Will copy in code from channel.go...
|
||||||
|
|
||||||
|
const (
|
||||||
|
MAX_STAGED_HTLCS = 1000
|
||||||
|
MAX_UNREVOKED_COMMITMENTS = 16
|
||||||
|
MAX_UPDATED_HTLCS_PER_COMMITMENT = 1000
|
||||||
|
)
|
||||||
|
|
||||||
|
//Currently, the mutex locks for across the entire channel, it's possible to
|
||||||
|
//update it to be more granular and to have each PaymentDescriptor have its own
|
||||||
|
//locks (and lock both simultaneously). However, this is complicated and will
|
||||||
|
//be updated in the future. Right now, since there is a per-channel
|
||||||
|
//global-lock, this should work fine...
|
||||||
|
//
|
||||||
|
//Before calling another function which does a lock, make sure to l.Unlock()
|
||||||
|
//first, e.g. if a packet received triggers a packet to be sent.
|
||||||
|
|
||||||
|
//PaymentDescriptor states
|
||||||
|
//PRESTAGE: We're not sure if the other guy wants to follow through
|
||||||
|
//STAGED: Both parties informally agree to add to their commitments
|
||||||
|
//SIGNING_AND_REVOKING: In the process of activating the HTLC
|
||||||
|
//
|
||||||
|
//Only one state is allowed at a time. timeout/settle can only begin on an
|
||||||
|
//ADD_COMPLETE state. If it times out before it hits completion, channel closes
|
||||||
|
//out uncooperatively.
|
||||||
|
//
|
||||||
|
//NOTE: Current design assumes if value%1000 == 200 as partially
|
||||||
|
//signed/revoked, this means that the code is reliant upon this as knowing when
|
||||||
|
//to force close out channels, etc.
|
||||||
|
const (
|
||||||
|
//HTLC Add
|
||||||
|
ADD_PRESTAGE = 1000
|
||||||
|
ADD_STAGED = 1100
|
||||||
|
ADD_SIGNING_AND_REVOKING = 1200
|
||||||
|
ADD_COMPLETE = 1300 //Most HTLCs should be this
|
||||||
|
ADD_REJECTED = 1999 //Staging request rejected
|
||||||
|
|
||||||
|
//HTLC Timeout
|
||||||
|
TIMEOUT_PRESTAGE = 2000
|
||||||
|
TIMEOUT_STAGED = 2100
|
||||||
|
TIMEOUT_SIGNING_AND_REVOKING = 2200
|
||||||
|
TIMEOUT_COMPLETE = 2300
|
||||||
|
|
||||||
|
//HTLC Settle
|
||||||
|
SETTLE_PRESTAGE = 3000
|
||||||
|
SETTLE_STAGED = 3100
|
||||||
|
SETTLE_SIGNING_AND_REVOKING = 3200
|
||||||
|
SETTLE_COMPLETE = 3300
|
||||||
|
|
||||||
|
//TODO: Commitment states
|
||||||
|
)
|
||||||
|
|
||||||
|
//Example, Add Flow:
|
||||||
|
//1. Create the HTLC
|
||||||
|
//2. (you+they) Sign the commit
|
||||||
|
//3. (you+they) Send revocation when you get a new commit
|
||||||
|
//4. Update the state to account for revocation
|
||||||
|
//5. Both sides committed and revoked prior states, mark state as finished
|
||||||
|
|
||||||
|
type LNChannel struct {
|
||||||
|
fundingTxIn *wire.TxIn
|
||||||
|
channelDB *channeldb.DB
|
||||||
|
|
||||||
|
channelID uint64
|
||||||
|
|
||||||
|
//The person who set up the channel is even, the person who responded
|
||||||
|
//is odd. All HTLCKeys use even/odd numbering.
|
||||||
|
//NOTE: should we change this to be a int64 and use positive/negative?
|
||||||
|
isEven bool
|
||||||
|
|
||||||
|
sync.RWMutex
|
||||||
|
|
||||||
|
//Should update with new Commitments when fees are renegotiated
|
||||||
|
feePerKb btcutil.Amount
|
||||||
|
|
||||||
|
//HTLCs
|
||||||
|
//Even/odd numbering in effect
|
||||||
|
//Will just take the next number
|
||||||
|
HTLCs map[lnwire.HTLCKey]*PaymentDescriptor
|
||||||
|
//Last key in the map for incrementing
|
||||||
|
//If the other party wants to use some stupid high number, then
|
||||||
|
//they're basically wanting the channel to close out early...
|
||||||
|
ourLastKey lnwire.HTLCKey
|
||||||
|
theirLastKey lnwire.HTLCKey
|
||||||
|
|
||||||
|
//ourCommit/theirCommit is the most recent *signed* Commitment
|
||||||
|
ourCommit *wire.MsgTx
|
||||||
|
theirCommit *wire.MsgTx
|
||||||
|
ourCommitHeight lnwire.CommitHeight
|
||||||
|
ourUnrevokedCommitments []lnwire.CommitHeight
|
||||||
|
theirCommitHeight lnwire.CommitHeight
|
||||||
|
theirUnrevokedCommitments []lnwire.CommitHeight
|
||||||
|
//UnrevoedStates indexed by CommitHeight, slice of HTLCKeys to update
|
||||||
|
//as revoked/complete
|
||||||
|
|
||||||
|
//NOTE: I think it's EASIER to reconstruct the Commitment than
|
||||||
|
//to update because finding indicies and blah blah blah,
|
||||||
|
//validation/verification screw that, the state is in the HTLCs
|
||||||
|
//and the sig. We can optimize later.
|
||||||
|
|
||||||
|
//ShaChain Height
|
||||||
|
//Difference between ourCommitHeight and ourShaChain index is the
|
||||||
|
//Commitments not yet revoked. If the difference is 1, then all prior
|
||||||
|
//Commitments are revoked.
|
||||||
|
ourShaChain *shachain.HyperShaChain
|
||||||
|
theirShaChain *shachain.HyperShaChain
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentDescriptor struct {
|
||||||
|
RHashes []*[20]byte
|
||||||
|
Timeout uint32
|
||||||
|
CreditsAmount lnwire.CreditsAmount
|
||||||
|
Revocation []*[20]byte
|
||||||
|
Blob []byte //next hop data
|
||||||
|
PayToUs bool
|
||||||
|
|
||||||
|
State uint32 //Current state
|
||||||
|
|
||||||
|
Index uint32 //Position in txout
|
||||||
|
p2sh [20]byte //cached p2sh script to use
|
||||||
|
|
||||||
|
//Used during the SIGNING_AND_REVOKING process
|
||||||
|
weSigned bool
|
||||||
|
theyRevoked bool
|
||||||
|
theySignedAndWeRevoked bool
|
||||||
|
//This is the height which is revoked, anything before that
|
||||||
|
//is assumed to still be valid.
|
||||||
|
//This data point is useful for ...UnrevokedCommitments
|
||||||
|
//if there's unrevoked commitments below these values,
|
||||||
|
//then the state is not locked in
|
||||||
|
//Used for add/settle/timeout
|
||||||
|
ourRevokedHeight lnwire.CommitHeight
|
||||||
|
theirRevokedHeight lnwire.CommitHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
//addHTLC will take in a PaymentDescriptor, adds to HTLCs and writes to disk
|
||||||
|
//Assumes the data has already been validated!
|
||||||
|
//NOTE: **MUST** HAVE THE MUTEX LOCKED ALREADY WHEN CALLED
|
||||||
|
func (l *LNChannel) addHTLC(h *PaymentDescriptor) (lnwire.HTLCKey, error) {
|
||||||
|
//Sanity check
|
||||||
|
if h.State != ADD_PRESTAGE {
|
||||||
|
return 0, fmt.Errorf("addHTLC can only add PRESTAGE")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Make sure we're not overfull
|
||||||
|
//We should *never* hit this...
|
||||||
|
//we subtract 3 in case we need to add one to correct for even/odd
|
||||||
|
if l.ourLastKey >= ^lnwire.HTLCKey(0)-3 {
|
||||||
|
return 0, fmt.Errorf("Channel full!!!")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assign a new value
|
||||||
|
//We add 2 due to even/odd assignments
|
||||||
|
l.ourLastKey += 2
|
||||||
|
|
||||||
|
//Check whether the even/odd is invalid..
|
||||||
|
//If it is, we iterate to the next one
|
||||||
|
if l.ourLastKey%1 == 1 {
|
||||||
|
if l.isEven {
|
||||||
|
l.ourLastKey += 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !l.isEven {
|
||||||
|
l.ourLastKey += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Write the new HTLC
|
||||||
|
l.HTLCs[l.ourLastKey] = h
|
||||||
|
disk() //save l.ourLastKey and the htlcs
|
||||||
|
|
||||||
|
return l.ourLastKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LNChannel) CreateHTLC(h *PaymentDescriptor) error {
|
||||||
|
l.Lock()
|
||||||
|
var err error
|
||||||
|
//if h.State == ADD_PRESTAGE {
|
||||||
|
// //We already have it created, but let's re-send!
|
||||||
|
// //Send a payment request LNWire
|
||||||
|
//}
|
||||||
|
if h.State > ADD_PRESTAGE {
|
||||||
|
l.Unlock()
|
||||||
|
return fmt.Errorf("HTLC is already created!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !h.PayToUs { //We created the payment
|
||||||
|
//Validate the data
|
||||||
|
err = l.validateHTLC(h, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//Update state as pre-commit
|
||||||
|
h.State = ADD_PRESTAGE
|
||||||
|
l.addHTLC(h)
|
||||||
|
//Send a ADDHTLC LNWire
|
||||||
|
l.Unlock()
|
||||||
|
net() //TODO
|
||||||
|
} else {
|
||||||
|
//Future version may be able to do this..
|
||||||
|
l.Unlock()
|
||||||
|
fmt.Errorf("Cannot pull money")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Receives an HTLCAddRequest message
|
||||||
|
//Adds to the HTLC staging list
|
||||||
|
func (l *LNChannel) recvHTLCAddRequest(p *lnwire.HTLCAddRequest) error {
|
||||||
|
l.Lock()
|
||||||
|
var err error
|
||||||
|
//Check if we already have a PaymentDescriptor
|
||||||
|
if l.HTLCs[p.HTLCKey] != nil {
|
||||||
|
//Don't do anything because we already have one
|
||||||
|
l.Unlock()
|
||||||
|
return fmt.Errorf("Counterparty attempted to re-send AddRequest")
|
||||||
|
}
|
||||||
|
//Make sure they aren't reusing
|
||||||
|
if p.HTLCKey <= l.theirLastKey {
|
||||||
|
//They're reusing.... uhoh
|
||||||
|
l.Unlock()
|
||||||
|
l.sendAddReject(p.HTLCKey) //This may be a dupe!
|
||||||
|
return fmt.Errorf("Counterparty cannot re-use HTLCKeys")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update newest id
|
||||||
|
l.theirLastKey = p.HTLCKey
|
||||||
|
|
||||||
|
//Create a new HTLCKey entry
|
||||||
|
htlc := new(PaymentDescriptor)
|
||||||
|
//Populate the entries
|
||||||
|
htlc.RHashes = p.RedemptionHashes
|
||||||
|
htlc.Timeout = p.Expiry
|
||||||
|
htlc.CreditsAmount = p.CreditsAmount
|
||||||
|
htlc.Blob = p.Blob
|
||||||
|
htlc.State = ADD_STAGED //mark as staged by both parties
|
||||||
|
htlc.PayToUs = true //assume this is paid to us, may change in the future
|
||||||
|
|
||||||
|
//Validate the HTLC
|
||||||
|
err = l.validateHTLC(htlc, true)
|
||||||
|
if err != nil {
|
||||||
|
//Update state just in case (not used but y'know..)
|
||||||
|
htlc.State = ADD_REJECTED
|
||||||
|
|
||||||
|
//currently not yet added to staging
|
||||||
|
//so we don't need to worry about the above htlc
|
||||||
|
//we also don't add to disk
|
||||||
|
|
||||||
|
//However, we do need to send a AddReject packet
|
||||||
|
l.Unlock()
|
||||||
|
sendAddReject(p.HTLCKey)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validation passed, so we continue
|
||||||
|
addHTLC(h)
|
||||||
|
|
||||||
|
//Send add accept packet, and we're done
|
||||||
|
l.Unlock()
|
||||||
|
sendAddAccept(p.HTLCKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LNChannel) sendAddReject(htlckey lnwire.HTLCKey) error {
|
||||||
|
l.Lock()
|
||||||
|
defer l.Unlock()
|
||||||
|
msg = new(lnwire.HTLCAddReject)
|
||||||
|
msg.ChannelID = l.channelID
|
||||||
|
msg.HTLCKey = h.HTLCKey
|
||||||
|
net(msg)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LNChannel) recvAddReject(htlckey lnwire.HTLCKey) error {
|
||||||
|
l.Lock()
|
||||||
|
defer l.Unlock()
|
||||||
|
htlc = l.HTLCs[htlckey]
|
||||||
|
if htlc == nil {
|
||||||
|
return fmt.Errorf("Counterparty rejected non-existent HTLC")
|
||||||
|
}
|
||||||
|
if (*htlc).State != ADD_PRESTAGE {
|
||||||
|
return fmt.Errorf("Counterparty atttempted to reject invalid state")
|
||||||
|
}
|
||||||
|
(*htlc).State = ADD_REJECTED
|
||||||
|
disk()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Notifies the other party that it is now staged on our end
|
||||||
|
func (l *LNChannel) sendAddAccept(htlckey lnwire.HTLCKey) error {
|
||||||
|
h = l.HTLCs[htlckey]
|
||||||
|
msg = new(lnwire.HTLCAddAccept)
|
||||||
|
msg.ChannelID = l.channelID
|
||||||
|
msg.HTLCKey = h.HTLCKey
|
||||||
|
|
||||||
|
disk()
|
||||||
|
net(msg)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//The other party has accepted the staging request, so we are staging now
|
||||||
|
func (l *LNChannel) recvAddAccept(p *HTLCAddAccept) error {
|
||||||
|
htlc = l.HTLCs[p.HTLCKey]
|
||||||
|
//Make sure it's in the list
|
||||||
|
if htlc == nil {
|
||||||
|
return fmt.Errorf("Counterparty accepted non-existent HTLC")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update pre-stage to staged
|
||||||
|
//Everything else it won't do anything
|
||||||
|
if (*htlc).State == ADD_PRESTAGE {
|
||||||
|
//Update to staged
|
||||||
|
(*htlc).State = ADD_STAGED
|
||||||
|
disk()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LNChannel) timeoutHTLC(htlcKey lnwire.HTLCKey) error {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LNChannel) settleHTLC(htlcKey lnwire.HTLCKey) error {
|
||||||
|
}
|
||||||
|
|
||||||
|
//receive AddAcceptHTLC: Find the HTLC and call createHTLC
|
||||||
|
func (l *LNChannel) addAccept(h *PaymentDescriptor) error {
|
||||||
|
if h.State == ADD_PRESTAGE {
|
||||||
|
//Mark stage as accepted
|
||||||
|
h.State = ADD_SIGNING_AND_REVOKING
|
||||||
|
//Write to disk
|
||||||
|
disk()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Timeout, Settle
|
||||||
|
|
||||||
|
//Create a commitment
|
||||||
|
// Update the markings on the HTLCs
|
||||||
|
func (l *LNChannel) createCommitment() error {
|
||||||
|
//Take all staging marked as SIGNING_AND_REVOKING *and* we have not signed
|
||||||
|
// Mark each as weSigned
|
||||||
|
}
|
||||||
|
|
||||||
|
//They revoke prior
|
||||||
|
//After we send a Commitment, they should send a revocation
|
||||||
|
// Update shaChain and HTLCs
|
||||||
|
func (l *LNChannel) receiveRevocation() error {
|
||||||
|
//Revoke the prior Commitment
|
||||||
|
//Update HTLCs with theyRevoked
|
||||||
|
//Check each HTLC for being complete and mark as complete if so
|
||||||
|
}
|
||||||
|
|
||||||
|
//Receive a commitment & send out a revocation
|
||||||
|
// Update the markings on the HTLCs
|
||||||
|
func (l *LNChannel) receiveCommitment() error {
|
||||||
|
//Validate new Commitment (sigs, even/odd for commitment height, incremental commitment height, etc)
|
||||||
|
// Reconstruct Commitment
|
||||||
|
//Update with new Commitment
|
||||||
|
//Send revocation
|
||||||
|
//Mark as theySignedAndWeRevoked
|
||||||
|
//Check each HTLC for being complete and mark as complete if so
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mark the HTLC as revoked if it is fully signed and revoked by both parties
|
||||||
|
func (l *LNChannel) addCompleteHTLC(h *PaymentDescriptor) error {
|
||||||
|
//Check/validate values
|
||||||
|
//Mark as ADD_COMPLETE
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validate whether we want to add the HTLC
|
||||||
|
func (l *LNChannel) validateHTLC(h *PaymentDescriptor, toUs bool) error {
|
||||||
|
//Make sure we have available spots; not too many outputs
|
||||||
|
//Make sure there is available funds
|
||||||
|
//Make sure there is sufficient reserve for fees
|
||||||
|
//Make sure the money is going in the right direction
|
||||||
|
}
|
181
lnwire/README.md
181
lnwire/README.md
@ -56,3 +56,184 @@ Close Complete
|
|||||||
Returns the Txid and sig as a courtesy. The counterparty might not send this if
|
Returns the Txid and sig as a courtesy. The counterparty might not send this if
|
||||||
they're being non-cooperative.
|
they're being non-cooperative.
|
||||||
|
|
||||||
|
Commitments and HTLCs
|
||||||
|
=====================
|
||||||
|
|
||||||
|
This is designed to be non-blocking where there can be multiple Commitments per
|
||||||
|
person and the Commitments do not need to match. A HTLC is only believed to be
|
||||||
|
added when it's in both parties' most recent Commitment (same with
|
||||||
|
timeout/settle).
|
||||||
|
|
||||||
|
As a result, there can easily be hundreds of state updates/payments per second
|
||||||
|
per channel.
|
||||||
|
|
||||||
|
Commitment States
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Commitments:
|
||||||
|
1. HTLCs, can be modified. Any add/settlement/timeout/etc. gets added to
|
||||||
|
staging.
|
||||||
|
2. Signed, only one signed state at a time can exist per party. Takes HTLCs
|
||||||
|
staging and locks it in, can now be broadcast on-chain by the counterparty.
|
||||||
|
3. Completed and Revoked, other party sends their revocation accepting this
|
||||||
|
Commitment. Sending a revocation means you *ACCEPT* the Commitment. There
|
||||||
|
should never be a case where a Commitment Signature happens and the client
|
||||||
|
refusees to revoke -- instead the client should immediately close out the
|
||||||
|
channel.
|
||||||
|
4. Deprecated, a commitment is old, marked as deprecated when there is a new
|
||||||
|
Commitment and this one is revoked. These commitments never be broadcasted.
|
||||||
|
5. Invalid, close out channel immediately.
|
||||||
|
|
||||||
|
There can be multiple commitments going at a time per party (currently limits a
|
||||||
|
total of 16 possible in-flight that can be broadcast for sanity, but there's no
|
||||||
|
real limit).
|
||||||
|
|
||||||
|
For validity, all you do is ensure that the changes from the old commitment are
|
||||||
|
legit (based on your HTLC/staging data)
|
||||||
|
COMMIT\_STAGING
|
||||||
|
COMMIT\_SIGNED
|
||||||
|
COMMIT\_COMPLETE
|
||||||
|
|
||||||
|
Messages:
|
||||||
|
CommitSignature: Signature to establish COMMIT\_SIGNED state
|
||||||
|
CommitRevocation: Revoke prior states
|
||||||
|
|
||||||
|
ADD HTLCs
|
||||||
|
---------
|
||||||
|
|
||||||
|
Requester Add HTLC states (Adding HTLCs):
|
||||||
|
1. Pre-staged, don't know if the other person wants it
|
||||||
|
2. Staged, both parties agree to add this HTLC. If a staging request packet is
|
||||||
|
received, then BOTH PARTIES will have it in their next Commitment. Nothing
|
||||||
|
is guaranteed here, but violations are treated as immediate channel closure.
|
||||||
|
3. Signed and sent the Commitment Tx to the counterparty, one should now assume
|
||||||
|
that there's a possibility that this HTLC will be boradcast on-chain.
|
||||||
|
4. Completed and Revoked, *counterparty* has included this in the Commitment
|
||||||
|
they're broadcasting and revoked their prior state. This means the
|
||||||
|
*Requeseter* can continue to take action, since the Commitment they have,
|
||||||
|
the HTLC doesn't exist (no payment), and the *Responder* will broadcast with
|
||||||
|
the payment to the *Responder*. However, the *Responder* cannot treat the
|
||||||
|
HTLC as cleared.
|
||||||
|
5. Cleared. Both parties have signed and revoked. Responder can continue
|
||||||
|
routing. Make sure it's included in *BOTH COMMITMENTS and ALL PREVIOUS
|
||||||
|
REVOKED*
|
||||||
|
6. Staging Reject, removal request, tx rejected, begin flow to reject HTLC from
|
||||||
|
other channels, can only be sent during the *pre-staging* state
|
||||||
|
|
||||||
|
In the event that an HTLC stays in "Completed and Revoked" and it is timed out,
|
||||||
|
and the counterparty refuses to add it into a new Commitment, the channel is
|
||||||
|
*closed out on-chain*. In other words, when checking which ones to send a
|
||||||
|
settle/timeout notification, do it for anything which is
|
||||||
|
ADD\_SIGNING\_AND\_REVOKING, *or* ADD\_COMPLETE (AND ALL OTHER PRE-COMPLETE
|
||||||
|
STAGES, e.g. in timeout or settlement).
|
||||||
|
|
||||||
|
As part of moving to any further stage, check if it's timed out.
|
||||||
|
|
||||||
|
If there is a request to stage and it's already staged, treat it as accepting.
|
||||||
|
|
||||||
|
When it has cleared and timed out, a timeout notification is sent.
|
||||||
|
|
||||||
|
HTLC ID numbers are uint64 and each counterparty is responsible to only make
|
||||||
|
sequential/incremental, and each party can only make evens/odds (odd channel
|
||||||
|
creation responder, evens channel creation initiator)
|
||||||
|
|
||||||
|
State is for *YOUR* signatures (what kind of action you need to do in the future)
|
||||||
|
ADD\_PRESTAGE
|
||||||
|
ADD\_STAGED
|
||||||
|
ADD\_SIGNING\_AND\_REVOKING
|
||||||
|
ADD\_COMPLETE
|
||||||
|
ADD\_REJECTED
|
||||||
|
|
||||||
|
Messages:
|
||||||
|
HTLCAddRequest: Request to add to staging
|
||||||
|
HTLCAddAccept: Add to staging (both parties have added when recv)
|
||||||
|
HTLCAddReject: Deny add to staging (both parties don't have in staging)
|
||||||
|
|
||||||
|
HTLC Settle (payment success)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Requester Settle HTLC states (Fulfill HTLCs):
|
||||||
|
1. Pre-staged, don't know if the other person will agree to settle
|
||||||
|
2. Staged, both parties agree to settle this HTLC
|
||||||
|
3. Signed and sent Commitment Tx to the counterparty, there is now the
|
||||||
|
possibility that the HTLC does not exist on-chain (of course, the Commitment
|
||||||
|
includes the payment so there's no real loss of funds). In the event that it
|
||||||
|
does not complete past this step, then one *must* close out on-chain as if
|
||||||
|
it was never staged/signed in the first place and the counterparty went
|
||||||
|
offline.
|
||||||
|
4. Both parties have signed and revoked, the settlement is complete (there is
|
||||||
|
no intermediate step of Revoked because this is only reliable and actionable
|
||||||
|
if BOTH PARTIES have updated their settlement state).
|
||||||
|
|
||||||
|
This has one less state because when adding, you're encumbering yourself. With
|
||||||
|
removing, both parties are potentially encumbered, so they cannot take action
|
||||||
|
until it's fully settled.
|
||||||
|
|
||||||
|
State is for *your* signatures
|
||||||
|
SETTLE\_PRESTAGE
|
||||||
|
SETTLE\_STAGED
|
||||||
|
SETTLE\_SIGNING\_AND\_REVOKING
|
||||||
|
SETTLE\_COMPLETE
|
||||||
|
|
||||||
|
Message:
|
||||||
|
HTLCSettleRequest: Request to add to staging the removal from Commitment.
|
||||||
|
HTLCSettleAccept: Add to staging the removal from Commitment.
|
||||||
|
(There is no HTLCSettleReject as the counterparty should immediately close out
|
||||||
|
or at worst ignore if it's getting garbage requests)
|
||||||
|
|
||||||
|
Timeout (falure/refund)
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Requester Timeout HTLC States:
|
||||||
|
1. Pre-staged
|
||||||
|
2. Staged, both parties agree to time out the HTLC and refund the money
|
||||||
|
3. Signe dnad sent commitment to the counterparty, there is now the possibility
|
||||||
|
that the transaction will no longer exist on-chain (of course, they can be
|
||||||
|
redeemed either way). In the even that it does not complete past this step,
|
||||||
|
then one *must* close out on-chain as if it was never staged/signed in the
|
||||||
|
first place adn the counterparty was offline.
|
||||||
|
4. Both parties have signed and revoked, the settlement is complete (there is no
|
||||||
|
intermediate step of Revoked because there is only reliable and actionable if
|
||||||
|
BOTH PARTIES have updated their settlement state).
|
||||||
|
|
||||||
|
Similar to HTLC Settlement, there is one less state.
|
||||||
|
|
||||||
|
State is for *your* signatures
|
||||||
|
TIMEOUT\_PRESTAGE
|
||||||
|
TIMEOUT\_STAGED
|
||||||
|
TIMEOUT\_SIGNING\_AND\_REVOKING
|
||||||
|
TIMEOUT\_COMPLETE
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
Adding a single HTLC process:
|
||||||
|
1. Requester flags as pre-staged, and sends an "add requeset"
|
||||||
|
2. Responder decides whether to add. If they don't, they invalidate it. If they
|
||||||
|
do, they send a message accepting the staging request. It is now marked as
|
||||||
|
staged on both sides and is ready to be accepted into a Commitment.
|
||||||
|
3. When a party wants to update with a new Commitment, they send a new signed
|
||||||
|
Commitment, this includes data that the HTLC is part of it. Let's say it's
|
||||||
|
the Requester that sends this new Commitment. As a result, the HTLC is
|
||||||
|
marked *BY THE RESPONDER* as Signed. It's only when the Responder includes a
|
||||||
|
transaction including the new HTLC in a new Commitment that the Requester
|
||||||
|
marks it as Signed.
|
||||||
|
4. Upon the Responder receiving the new Commitment, they send the revocation
|
||||||
|
for the old Commitment, and commit to broadcasting only the new one.
|
||||||
|
5. The *Requester* marks the HTLC as complete, but the *Responder* waits until
|
||||||
|
they receive a Commitment (and the old one is revoked) before marking it as
|
||||||
|
complete on the Responder's end.
|
||||||
|
6. When both parties have the new Commitments and the old ones are revoked,
|
||||||
|
then the HTLC is marked as complete
|
||||||
|
|
||||||
|
The two Commitment Transactions may not be completely in sync, but that's OK!
|
||||||
|
What's added in both (and removed in both) are regarded as valid and locked-in.
|
||||||
|
If it's only added to one, then it's regarded as in-transit and can go either
|
||||||
|
way.
|
||||||
|
|
||||||
|
The behavior is to sign after all additions/removals/cancellations, but there
|
||||||
|
may be multiple in the staging buffer.
|
||||||
|
|
||||||
|
Each party has their own revocation height (*for the other party to use*), and
|
||||||
|
they may be different.
|
||||||
|
@ -21,12 +21,8 @@ type CommitSignature struct {
|
|||||||
//each part of the Commitment.
|
//each part of the Commitment.
|
||||||
CommitmentHeight uint64
|
CommitmentHeight uint64
|
||||||
|
|
||||||
//The last staging included by both parties
|
//List of HTLC Keys which are updated from all parties
|
||||||
//Basically, the state is updated to this point on both parties'
|
UpdatedHTLCKeys []uint64
|
||||||
//staging
|
|
||||||
//Staging inclusion is in order.
|
|
||||||
CommitterLastStaging uint64
|
|
||||||
ReceiverLastStaging uint64
|
|
||||||
|
|
||||||
//Hash of the revocation to use
|
//Hash of the revocation to use
|
||||||
RevocationHash [20]byte
|
RevocationHash [20]byte
|
||||||
@ -41,16 +37,14 @@ type CommitSignature struct {
|
|||||||
func (c *CommitSignature) Decode(r io.Reader, pver uint32) error {
|
func (c *CommitSignature) Decode(r io.Reader, pver uint32) error {
|
||||||
//ChannelID(8)
|
//ChannelID(8)
|
||||||
//CommitmentHeight(8)
|
//CommitmentHeight(8)
|
||||||
//CommiterLastStaging(8)
|
//c.UpdatedHTLCKeys(8*1000max)
|
||||||
//ReceiverLastStaging(8)
|
|
||||||
//RevocationHash(20)
|
//RevocationHash(20)
|
||||||
//Fee(8)
|
//Fee(8)
|
||||||
//RequesterCommitSig(73max+2)
|
//RequesterCommitSig(73max+2)
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.CommitmentHeight,
|
&c.CommitmentHeight,
|
||||||
&c.CommitterLastStaging,
|
&c.UpdatedHTLCKeys,
|
||||||
&c.ReceiverLastStaging,
|
|
||||||
&c.RevocationHash,
|
&c.RevocationHash,
|
||||||
&c.Fee,
|
&c.Fee,
|
||||||
&c.CommitSig,
|
&c.CommitSig,
|
||||||
@ -73,8 +67,7 @@ func (c *CommitSignature) Encode(w io.Writer, pver uint32) error {
|
|||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.CommitmentHeight,
|
c.CommitmentHeight,
|
||||||
c.CommitterLastStaging,
|
c.UpdatedHTLCKeys,
|
||||||
c.ReceiverLastStaging,
|
|
||||||
c.RevocationHash,
|
c.RevocationHash,
|
||||||
c.Fee,
|
c.Fee,
|
||||||
c.CommitSig,
|
c.CommitSig,
|
||||||
@ -91,7 +84,7 @@ func (c *CommitSignature) Command() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommitSignature) MaxPayloadLength(uint32) uint32 {
|
func (c *CommitSignature) MaxPayloadLength(uint32) uint32 {
|
||||||
return 135
|
return 8192
|
||||||
}
|
}
|
||||||
|
|
||||||
//Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
|
//Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
|
||||||
@ -108,21 +101,23 @@ func (c *CommitSignature) Validate() error {
|
|||||||
func (c *CommitSignature) String() string {
|
func (c *CommitSignature) String() string {
|
||||||
//c.ChannelID,
|
//c.ChannelID,
|
||||||
//c.CommitmentHeight,
|
//c.CommitmentHeight,
|
||||||
//c.CommitterLastStaging,
|
|
||||||
//c.ReceiverLastStaging,
|
|
||||||
//c.RevocationHash,
|
//c.RevocationHash,
|
||||||
|
//c.UpdatedHTLCKeys,
|
||||||
//c.Fee,
|
//c.Fee,
|
||||||
//c.CommitSig,
|
//c.CommitSig,
|
||||||
var serializedSig []byte
|
var serializedSig []byte
|
||||||
if &c.CommitSig != nil && c.CommitSig.R != nil {
|
if &c.CommitSig != nil && c.CommitSig.R != nil {
|
||||||
serializedSig = c.CommitSig.Serialize()
|
serializedSig = c.CommitSig.Serialize()
|
||||||
}
|
}
|
||||||
|
var items string
|
||||||
|
for i := 0; i < len(c.UpdatedHTLCKeys); i++ {
|
||||||
|
items += fmt.Sprintf("%d ", c.UpdatedHTLCKeys[i])
|
||||||
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("\n--- Begin CommitSignature ---\n") +
|
return fmt.Sprintf("\n--- Begin CommitSignature ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("CommitmentHeight:\t%d\n", c.CommitmentHeight) +
|
fmt.Sprintf("CommitmentHeight:\t%d\n", c.CommitmentHeight) +
|
||||||
fmt.Sprintf("CommitterLastStaging:\t%d\n", c.CommitterLastStaging) +
|
fmt.Sprintf("UpdatedHTLCKeys:\t%s\n", items) +
|
||||||
fmt.Sprintf("ReceiverLastStaging:\t%d\n", c.ReceiverLastStaging) +
|
|
||||||
fmt.Sprintf("RevocationHash:\t\t%x\n", c.RevocationHash) +
|
fmt.Sprintf("RevocationHash:\t\t%x\n", c.RevocationHash) +
|
||||||
fmt.Sprintf("Fee:\t\t\t%s\n", c.Fee.String()) +
|
fmt.Sprintf("Fee:\t\t\t%s\n", c.Fee.String()) +
|
||||||
fmt.Sprintf("CommitSig:\t\t%x\n", serializedSig) +
|
fmt.Sprintf("CommitSig:\t\t%x\n", serializedSig) +
|
||||||
|
@ -10,16 +10,16 @@ var (
|
|||||||
_ = copy(revocationHash[:], revocationHashBytes)
|
_ = copy(revocationHash[:], revocationHashBytes)
|
||||||
|
|
||||||
commitSignature = &CommitSignature{
|
commitSignature = &CommitSignature{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
CommitmentHeight: uint64(12345),
|
CommitmentHeight: uint64(12345),
|
||||||
CommitterLastStaging: uint64(12345678),
|
//CommitterLastStaging: uint64(12345678),
|
||||||
ReceiverLastStaging: uint64(87654321),
|
UpdatedHTLCKeys: []uint64{1, 2, 3, 4, 5},
|
||||||
RevocationHash: revocationHash,
|
RevocationHash: revocationHash,
|
||||||
Fee: btcutil.Amount(10000),
|
Fee: btcutil.Amount(10000),
|
||||||
CommitSig: commitSig,
|
CommitSig: commitSig,
|
||||||
}
|
}
|
||||||
commitSignatureSerializedString = "0000000000bc614e00000000000030390000000000bc614e0000000005397fb14132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
commitSignatureSerializedString = "0000000000bc614e00000000000030390005000000000000000100000000000000020000000000000003000000000000000400000000000000054132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
||||||
commitSignatureSerializedMessage = "0709110b000007d0000000830000000000bc614e00000000000030390000000000bc614e0000000005397fb14132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
commitSignatureSerializedMessage = "0709110b000007d00000009d0000000000bc614e00000000000030390005000000000000000100000000000000020000000000000003000000000000000400000000000000054132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommitSignatureEncodeDecode(t *testing.T) {
|
func TestCommitSignatureEncodeDecode(t *testing.T) {
|
||||||
|
@ -7,18 +7,15 @@ import (
|
|||||||
|
|
||||||
type HTLCAddAccept struct {
|
type HTLCAddAccept struct {
|
||||||
ChannelID uint64
|
ChannelID uint64
|
||||||
StagingID uint64
|
HTLCKey HTLCKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTLCAddAccept) Decode(r io.Reader, pver uint32) error {
|
func (c *HTLCAddAccept) Decode(r io.Reader, pver uint32) error {
|
||||||
//ChannelID(8)
|
//ChannelID(8)
|
||||||
//CommitmentHeight(8)
|
//HTLCKey(8)
|
||||||
//NextResponderCommitmentRevocationHash(20)
|
|
||||||
//ResponderRevocationPreimage(20)
|
|
||||||
//ResponderCommitSig(2+73max)
|
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.StagingID,
|
&c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -37,7 +34,7 @@ func NewHTLCAddAccept() *HTLCAddAccept {
|
|||||||
func (c *HTLCAddAccept) Encode(w io.Writer, pver uint32) error {
|
func (c *HTLCAddAccept) Encode(w io.Writer, pver uint32) error {
|
||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.StagingID,
|
c.HTLCKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,6 +62,6 @@ func (c *HTLCAddAccept) Validate() error {
|
|||||||
func (c *HTLCAddAccept) String() string {
|
func (c *HTLCAddAccept) String() string {
|
||||||
return fmt.Sprintf("\n--- Begin HTLCAddAccept ---\n") +
|
return fmt.Sprintf("\n--- Begin HTLCAddAccept ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("StagingID:\t\t%d\n", c.StagingID) +
|
fmt.Sprintf("HTLCKey:\t\t%d\n", c.HTLCKey) +
|
||||||
fmt.Sprintf("--- End HTLCAddAccept ---\n")
|
fmt.Sprintf("--- End HTLCAddAccept ---\n")
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
htlcAddAccept = &HTLCAddAccept{
|
htlcAddAccept = &HTLCAddAccept{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
StagingID: uint64(12345),
|
HTLCKey: HTLCKey(12345),
|
||||||
}
|
}
|
||||||
htlcAddAcceptSerializedString = "0000000000bc614e0000000000003039"
|
htlcAddAcceptSerializedString = "0000000000bc614e0000000000003039"
|
||||||
htlcAddAcceptSerializedMessage = "0709110b000003f2000000100000000000bc614e0000000000003039"
|
htlcAddAcceptSerializedMessage = "0709110b000003f2000000100000000000bc614e0000000000003039"
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
type HTLCAddReject struct {
|
type HTLCAddReject struct {
|
||||||
ChannelID uint64
|
ChannelID uint64
|
||||||
StagingID uint64
|
HTLCKey HTLCKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error {
|
func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error {
|
||||||
@ -18,7 +18,7 @@ func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error {
|
|||||||
//ResponderCommitSig(2+73max)
|
//ResponderCommitSig(2+73max)
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.StagingID,
|
&c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -37,7 +37,7 @@ func NewHTLCAddReject() *HTLCAddReject {
|
|||||||
func (c *HTLCAddReject) Encode(w io.Writer, pver uint32) error {
|
func (c *HTLCAddReject) Encode(w io.Writer, pver uint32) error {
|
||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.StagingID,
|
c.HTLCKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,6 +65,6 @@ func (c *HTLCAddReject) Validate() error {
|
|||||||
func (c *HTLCAddReject) String() string {
|
func (c *HTLCAddReject) String() string {
|
||||||
return fmt.Sprintf("\n--- Begin HTLCAddReject ---\n") +
|
return fmt.Sprintf("\n--- Begin HTLCAddReject ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("StagingID:\t\t%d\n", c.StagingID) +
|
fmt.Sprintf("HTLCKey:\t\t%d\n", c.HTLCKey) +
|
||||||
fmt.Sprintf("--- End HTLCAddReject ---\n")
|
fmt.Sprintf("--- End HTLCAddReject ---\n")
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
htlcAddReject = &HTLCAddReject{
|
htlcAddReject = &HTLCAddReject{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
StagingID: uint64(12345),
|
HTLCKey: HTLCKey(12345),
|
||||||
}
|
}
|
||||||
htlcAddRejectSerializedString = "0000000000bc614e0000000000003039"
|
htlcAddRejectSerializedString = "0000000000bc614e0000000000003039"
|
||||||
htlcAddRejectSerializedMessage = "0709110b000003fc000000100000000000bc614e0000000000003039"
|
htlcAddRejectSerializedMessage = "0709110b000003fc000000100000000000bc614e0000000000003039"
|
||||||
|
@ -12,7 +12,7 @@ type HTLCAddRequest struct {
|
|||||||
ChannelID uint64
|
ChannelID uint64
|
||||||
|
|
||||||
//ID of this request
|
//ID of this request
|
||||||
StagingID uint64
|
HTLCKey HTLCKey
|
||||||
|
|
||||||
//When the HTLC expires
|
//When the HTLC expires
|
||||||
Expiry uint32
|
Expiry uint32
|
||||||
@ -21,8 +21,9 @@ type HTLCAddRequest struct {
|
|||||||
//Difference between hop and first item in blob is the fee to complete
|
//Difference between hop and first item in blob is the fee to complete
|
||||||
Amount CreditsAmount
|
Amount CreditsAmount
|
||||||
|
|
||||||
//Hash160 address of the next hop.
|
//RefundContext is for payment cancellation
|
||||||
NextHop [20]byte
|
//TODO (j): not currently in use, add later
|
||||||
|
RefundContext HTLCKey
|
||||||
|
|
||||||
//Contract Type
|
//Contract Type
|
||||||
//first 4 bits is n, second for is m, in n-of-m "multisig"
|
//first 4 bits is n, second for is m, in n-of-m "multisig"
|
||||||
@ -38,19 +39,17 @@ type HTLCAddRequest struct {
|
|||||||
|
|
||||||
func (c *HTLCAddRequest) Decode(r io.Reader, pver uint32) error {
|
func (c *HTLCAddRequest) Decode(r io.Reader, pver uint32) error {
|
||||||
//ChannelID(8)
|
//ChannelID(8)
|
||||||
//StagingID(8)
|
//HTLCKey(8)
|
||||||
//Expiry(4)
|
//Expiry(4)
|
||||||
//Amount(4)
|
//Amount(4)
|
||||||
//NextHop(20)
|
|
||||||
//ContractType(1)
|
//ContractType(1)
|
||||||
//RedemptionHashes (numOfHashes * 20 + numOfHashes)
|
//RedemptionHashes (numOfHashes * 20 + numOfHashes)
|
||||||
//Blob(2+blobsize)
|
//Blob(2+blobsize)
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.StagingID,
|
&c.HTLCKey,
|
||||||
&c.Expiry,
|
&c.Expiry,
|
||||||
&c.Amount,
|
&c.Amount,
|
||||||
&c.NextHop,
|
|
||||||
&c.ContractType,
|
&c.ContractType,
|
||||||
&c.RedemptionHashes,
|
&c.RedemptionHashes,
|
||||||
&c.Blob,
|
&c.Blob,
|
||||||
@ -72,10 +71,9 @@ func NewHTLCAddRequest() *HTLCAddRequest {
|
|||||||
func (c *HTLCAddRequest) Encode(w io.Writer, pver uint32) error {
|
func (c *HTLCAddRequest) Encode(w io.Writer, pver uint32) error {
|
||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.StagingID,
|
c.HTLCKey,
|
||||||
c.Expiry,
|
c.Expiry,
|
||||||
c.Amount,
|
c.Amount,
|
||||||
c.NextHop,
|
|
||||||
c.ContractType,
|
c.ContractType,
|
||||||
c.RedemptionHashes,
|
c.RedemptionHashes,
|
||||||
c.Blob,
|
c.Blob,
|
||||||
@ -117,10 +115,9 @@ func (c *HTLCAddRequest) String() string {
|
|||||||
|
|
||||||
return fmt.Sprintf("\n--- Begin HTLCAddRequest ---\n") +
|
return fmt.Sprintf("\n--- Begin HTLCAddRequest ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("StagingID:\t%d\n", c.StagingID) +
|
fmt.Sprintf("HTLCKey:\t%d\n", c.HTLCKey) +
|
||||||
fmt.Sprintf("Expiry:\t\t%d\n", c.Expiry) +
|
fmt.Sprintf("Expiry:\t\t%d\n", c.Expiry) +
|
||||||
fmt.Sprintf("Amount\t\t%d\n", c.Amount) +
|
fmt.Sprintf("Amount\t\t%d\n", c.Amount) +
|
||||||
fmt.Sprintf("NextHop\t\t%x\n", c.NextHop) +
|
|
||||||
fmt.Sprintf("ContractType:\t%d (%b)\n", c.ContractType, c.ContractType) +
|
fmt.Sprintf("ContractType:\t%d (%b)\n", c.ContractType, c.ContractType) +
|
||||||
fmt.Sprintf("RedemptionHashes:") +
|
fmt.Sprintf("RedemptionHashes:") +
|
||||||
redemptionHashes +
|
redemptionHashes +
|
||||||
|
@ -8,23 +8,21 @@ var (
|
|||||||
//Need to to do this here
|
//Need to to do this here
|
||||||
_ = copy(revocationHash[:], revocationHashBytes)
|
_ = copy(revocationHash[:], revocationHashBytes)
|
||||||
_ = copy(redemptionHash[:], redemptionHashBytes)
|
_ = copy(redemptionHash[:], redemptionHashBytes)
|
||||||
_ = copy(nextHop[:], nextHopBytes)
|
|
||||||
emptyRedemptionHashes = []*[20]byte{}
|
emptyRedemptionHashes = []*[20]byte{}
|
||||||
redemptionHashes = append(emptyRedemptionHashes, &redemptionHash)
|
redemptionHashes = append(emptyRedemptionHashes, &redemptionHash)
|
||||||
|
|
||||||
htlcAddRequest = &HTLCAddRequest{
|
htlcAddRequest = &HTLCAddRequest{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
StagingID: uint64(12345),
|
HTLCKey: HTLCKey(12345),
|
||||||
Expiry: uint32(144),
|
Expiry: uint32(144),
|
||||||
Amount: CreditsAmount(123456000),
|
Amount: CreditsAmount(123456000),
|
||||||
NextHop: nextHop,
|
|
||||||
ContractType: uint8(17),
|
ContractType: uint8(17),
|
||||||
RedemptionHashes: redemptionHashes,
|
RedemptionHashes: redemptionHashes,
|
||||||
|
|
||||||
Blob: []byte{255, 0, 255, 0, 255, 0, 255, 0},
|
Blob: []byte{255, 0, 255, 0, 255, 0, 255, 0},
|
||||||
}
|
}
|
||||||
htlcAddRequestSerializedString = "0000000000bc614e000000000000303900000090075bca0094a9ded5a30fc5944cb1e2cbcd980f30616a14401100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
htlcAddRequestSerializedString = "0000000000bc614e000000000000303900000090075bca001100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
||||||
htlcAddRequestSerializedMessage = "0709110b000003e80000004d0000000000bc614e000000000000303900000090075bca0094a9ded5a30fc5944cb1e2cbcd980f30616a14401100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
htlcAddRequestSerializedMessage = "0709110b000003e8000000390000000000bc614e000000000000303900000090075bca001100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHTLCAddRequestEncodeDecode(t *testing.T) {
|
func TestHTLCAddRequestEncodeDecode(t *testing.T) {
|
||||||
|
@ -12,15 +12,15 @@ type HTLCSettleAccept struct {
|
|||||||
ChannelID uint64
|
ChannelID uint64
|
||||||
|
|
||||||
//ID of this request
|
//ID of this request
|
||||||
StagingID uint64
|
HTLCKey HTLCKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTLCSettleAccept) Decode(r io.Reader, pver uint32) error {
|
func (c *HTLCSettleAccept) Decode(r io.Reader, pver uint32) error {
|
||||||
//ChannelID(8)
|
//ChannelID(8)
|
||||||
//StagingID(8)
|
//HTLCKey(8)
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.StagingID,
|
&c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -39,7 +39,7 @@ func NewHTLCSettleAccept() *HTLCSettleAccept {
|
|||||||
func (c *HTLCSettleAccept) Encode(w io.Writer, pver uint32) error {
|
func (c *HTLCSettleAccept) Encode(w io.Writer, pver uint32) error {
|
||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.StagingID,
|
c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -66,6 +66,6 @@ func (c *HTLCSettleAccept) Validate() error {
|
|||||||
func (c *HTLCSettleAccept) String() string {
|
func (c *HTLCSettleAccept) String() string {
|
||||||
return fmt.Sprintf("\n--- Begin HTLCSettleAccept ---\n") +
|
return fmt.Sprintf("\n--- Begin HTLCSettleAccept ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("StagingID:\t%d\n", c.StagingID) +
|
fmt.Sprintf("HTLCKey:\t%d\n", c.HTLCKey) +
|
||||||
fmt.Sprintf("--- End HTLCSettleAccept ---\n")
|
fmt.Sprintf("--- End HTLCSettleAccept ---\n")
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
htlcSettleAccept = &HTLCSettleAccept{
|
htlcSettleAccept = &HTLCSettleAccept{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
StagingID: uint64(12345),
|
HTLCKey: HTLCKey(12345),
|
||||||
}
|
}
|
||||||
htlcSettleAcceptSerializedString = "0000000000bc614e0000000000003039"
|
htlcSettleAcceptSerializedString = "0000000000bc614e0000000000003039"
|
||||||
htlcSettleAcceptSerializedMessage = "0709110b00000456000000100000000000bc614e0000000000003039"
|
htlcSettleAcceptSerializedMessage = "0709110b00000456000000100000000000bc614e0000000000003039"
|
||||||
|
@ -12,7 +12,7 @@ type HTLCSettleRequest struct {
|
|||||||
ChannelID uint64
|
ChannelID uint64
|
||||||
|
|
||||||
//ID of this request
|
//ID of this request
|
||||||
StagingID uint64
|
HTLCKey HTLCKey
|
||||||
|
|
||||||
//Redemption Proofs (R-Values)
|
//Redemption Proofs (R-Values)
|
||||||
RedemptionProofs []*[20]byte
|
RedemptionProofs []*[20]byte
|
||||||
@ -20,7 +20,7 @@ type HTLCSettleRequest struct {
|
|||||||
|
|
||||||
func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
|
func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
|
||||||
//ChannelID(8)
|
//ChannelID(8)
|
||||||
//StagingID(8)
|
//HTLCKey(8)
|
||||||
//Expiry(4)
|
//Expiry(4)
|
||||||
//Amount(4)
|
//Amount(4)
|
||||||
//NextHop(20)
|
//NextHop(20)
|
||||||
@ -29,7 +29,7 @@ func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
|
|||||||
//Blob(2+blobsize)
|
//Blob(2+blobsize)
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.StagingID,
|
&c.HTLCKey,
|
||||||
&c.RedemptionProofs,
|
&c.RedemptionProofs,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -49,7 +49,7 @@ func NewHTLCSettleRequest() *HTLCSettleRequest {
|
|||||||
func (c *HTLCSettleRequest) Encode(w io.Writer, pver uint32) error {
|
func (c *HTLCSettleRequest) Encode(w io.Writer, pver uint32) error {
|
||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.StagingID,
|
c.HTLCKey,
|
||||||
c.RedemptionProofs,
|
c.RedemptionProofs,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -83,7 +83,7 @@ func (c *HTLCSettleRequest) String() string {
|
|||||||
|
|
||||||
return fmt.Sprintf("\n--- Begin HTLCSettleRequest ---\n") +
|
return fmt.Sprintf("\n--- Begin HTLCSettleRequest ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("StagingID:\t%d\n", c.StagingID) +
|
fmt.Sprintf("HTLCKey:\t%d\n", c.HTLCKey) +
|
||||||
fmt.Sprintf("RedemptionHashes:") +
|
fmt.Sprintf("RedemptionHashes:") +
|
||||||
redemptionProofs +
|
redemptionProofs +
|
||||||
fmt.Sprintf("--- End HTLCSettleRequest ---\n")
|
fmt.Sprintf("--- End HTLCSettleRequest ---\n")
|
||||||
|
@ -12,7 +12,7 @@ var (
|
|||||||
|
|
||||||
htlcSettleRequest = &HTLCSettleRequest{
|
htlcSettleRequest = &HTLCSettleRequest{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
StagingID: uint64(12345),
|
HTLCKey: HTLCKey(12345),
|
||||||
RedemptionProofs: redemptionProofs,
|
RedemptionProofs: redemptionProofs,
|
||||||
}
|
}
|
||||||
htlcSettleRequestSerializedString = "0000000000bc614e000000000000303900015b315ebabb0d8c0d94281caa2dfee69a1a00436e"
|
htlcSettleRequestSerializedString = "0000000000bc614e000000000000303900015b315ebabb0d8c0d94281caa2dfee69a1a00436e"
|
||||||
|
@ -12,15 +12,15 @@ type HTLCTimeoutAccept struct {
|
|||||||
ChannelID uint64
|
ChannelID uint64
|
||||||
|
|
||||||
//ID of this request
|
//ID of this request
|
||||||
StagingID uint64
|
HTLCKey HTLCKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTLCTimeoutAccept) Decode(r io.Reader, pver uint32) error {
|
func (c *HTLCTimeoutAccept) Decode(r io.Reader, pver uint32) error {
|
||||||
//ChannelID(8)
|
//ChannelID(8)
|
||||||
//StagingID(8)
|
//HTLCKey(8)
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.StagingID,
|
&c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -39,7 +39,7 @@ func NewHTLCTimeoutAccept() *HTLCTimeoutAccept {
|
|||||||
func (c *HTLCTimeoutAccept) Encode(w io.Writer, pver uint32) error {
|
func (c *HTLCTimeoutAccept) Encode(w io.Writer, pver uint32) error {
|
||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.StagingID,
|
c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -66,6 +66,6 @@ func (c *HTLCTimeoutAccept) Validate() error {
|
|||||||
func (c *HTLCTimeoutAccept) String() string {
|
func (c *HTLCTimeoutAccept) String() string {
|
||||||
return fmt.Sprintf("\n--- Begin HTLCTimeoutAccept ---\n") +
|
return fmt.Sprintf("\n--- Begin HTLCTimeoutAccept ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("StagingID:\t%d\n", c.StagingID) +
|
fmt.Sprintf("HTLCKey:\t%d\n", c.HTLCKey) +
|
||||||
fmt.Sprintf("--- End HTLCTimeoutAccept ---\n")
|
fmt.Sprintf("--- End HTLCTimeoutAccept ---\n")
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
htlcTimeoutAccept = &HTLCTimeoutAccept{
|
htlcTimeoutAccept = &HTLCTimeoutAccept{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
StagingID: uint64(12345),
|
HTLCKey: HTLCKey(12345),
|
||||||
}
|
}
|
||||||
htlcTimeoutAcceptSerializedString = "0000000000bc614e0000000000003039"
|
htlcTimeoutAcceptSerializedString = "0000000000bc614e0000000000003039"
|
||||||
htlcTimeoutAcceptSerializedMessage = "0709110b0000051e000000100000000000bc614e0000000000003039"
|
htlcTimeoutAcceptSerializedMessage = "0709110b0000051e000000100000000000bc614e0000000000003039"
|
||||||
|
@ -12,15 +12,15 @@ type HTLCTimeoutRequest struct {
|
|||||||
ChannelID uint64
|
ChannelID uint64
|
||||||
|
|
||||||
//ID of this request
|
//ID of this request
|
||||||
StagingID uint64
|
HTLCKey HTLCKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error {
|
func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error {
|
||||||
//ChannelID(8)
|
//ChannelID(8)
|
||||||
//StagingID(8)
|
//HTLCKey(8)
|
||||||
err := readElements(r,
|
err := readElements(r,
|
||||||
&c.ChannelID,
|
&c.ChannelID,
|
||||||
&c.StagingID,
|
&c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -39,7 +39,7 @@ func NewHTLCTimeoutRequest() *HTLCTimeoutRequest {
|
|||||||
func (c *HTLCTimeoutRequest) Encode(w io.Writer, pver uint32) error {
|
func (c *HTLCTimeoutRequest) Encode(w io.Writer, pver uint32) error {
|
||||||
err := writeElements(w,
|
err := writeElements(w,
|
||||||
c.ChannelID,
|
c.ChannelID,
|
||||||
c.StagingID,
|
c.HTLCKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -66,6 +66,6 @@ func (c *HTLCTimeoutRequest) Validate() error {
|
|||||||
func (c *HTLCTimeoutRequest) String() string {
|
func (c *HTLCTimeoutRequest) String() string {
|
||||||
return fmt.Sprintf("\n--- Begin HTLCTimeoutRequest ---\n") +
|
return fmt.Sprintf("\n--- Begin HTLCTimeoutRequest ---\n") +
|
||||||
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
|
||||||
fmt.Sprintf("StagingID:\t%d\n", c.StagingID) +
|
fmt.Sprintf("HTLCKey:\t%d\n", c.HTLCKey) +
|
||||||
fmt.Sprintf("--- End HTLCTimeoutRequest ---\n")
|
fmt.Sprintf("--- End HTLCTimeoutRequest ---\n")
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
htlcTimeoutRequest = &HTLCTimeoutRequest{
|
htlcTimeoutRequest = &HTLCTimeoutRequest{
|
||||||
ChannelID: uint64(12345678),
|
ChannelID: uint64(12345678),
|
||||||
StagingID: uint64(12345),
|
HTLCKey: HTLCKey(12345),
|
||||||
}
|
}
|
||||||
htlcTimeoutRequestSerializedString = "0000000000bc614e0000000000003039"
|
htlcTimeoutRequestSerializedString = "0000000000bc614e0000000000003039"
|
||||||
htlcTimeoutRequestSerializedMessage = "0709110b00000514000000100000000000bc614e0000000000003039"
|
htlcTimeoutRequestSerializedMessage = "0709110b00000514000000100000000000bc614e0000000000003039"
|
||||||
|
@ -16,6 +16,9 @@ var MAX_SLICE_LENGTH = 65535
|
|||||||
//Actual pkScript, not redeemScript
|
//Actual pkScript, not redeemScript
|
||||||
type PkScript []byte
|
type PkScript []byte
|
||||||
|
|
||||||
|
type HTLCKey uint64
|
||||||
|
type CommitHeight uint64
|
||||||
|
|
||||||
//Subsatoshi amount (Micro-Satoshi, 1/1000th)
|
//Subsatoshi amount (Micro-Satoshi, 1/1000th)
|
||||||
//Should be a signed int to account for negative fees
|
//Should be a signed int to account for negative fees
|
||||||
//
|
//
|
||||||
@ -76,6 +79,11 @@ func writeElement(w io.Writer, element interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
case HTLCKey:
|
||||||
|
err = writeElement(w, uint64(e))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case btcutil.Amount:
|
case btcutil.Amount:
|
||||||
err = binary.Write(w, binary.BigEndian, int64(e))
|
err = binary.Write(w, binary.BigEndian, int64(e))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -94,6 +102,24 @@ func writeElement(w io.Writer, element interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
case []uint64:
|
||||||
|
numItems := len(e)
|
||||||
|
if numItems > 65535 {
|
||||||
|
return fmt.Errorf("Too many []uint64s")
|
||||||
|
}
|
||||||
|
//Write the size
|
||||||
|
err = writeElement(w, uint16(numItems))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//Write the data
|
||||||
|
for i := 0; i < numItems; i++ {
|
||||||
|
err = writeElement(w, e[i])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
case []*btcec.Signature:
|
case []*btcec.Signature:
|
||||||
numSigs := len(e)
|
numSigs := len(e)
|
||||||
if numSigs > 127 {
|
if numSigs > 127 {
|
||||||
@ -313,6 +339,14 @@ func readElement(r io.Reader, element interface{}) error {
|
|||||||
}
|
}
|
||||||
*e = binary.BigEndian.Uint64(b[:])
|
*e = binary.BigEndian.Uint64(b[:])
|
||||||
return nil
|
return nil
|
||||||
|
case *HTLCKey:
|
||||||
|
var b [8]byte
|
||||||
|
_, err = io.ReadFull(r, b[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = HTLCKey(binary.BigEndian.Uint64(b[:]))
|
||||||
|
return nil
|
||||||
case *btcutil.Amount:
|
case *btcutil.Amount:
|
||||||
var b [8]byte
|
var b [8]byte
|
||||||
_, err = io.ReadFull(r, b[:])
|
_, err = io.ReadFull(r, b[:])
|
||||||
@ -341,6 +375,28 @@ func readElement(r io.Reader, element interface{}) error {
|
|||||||
}
|
}
|
||||||
*e = &*x
|
*e = &*x
|
||||||
return nil
|
return nil
|
||||||
|
case *[]uint64:
|
||||||
|
var numItems uint16
|
||||||
|
err = readElement(r, &numItems)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//if numItems > 65535 {
|
||||||
|
// return fmt.Errorf("Too many items in []uint64")
|
||||||
|
//}
|
||||||
|
|
||||||
|
//Read the number of items
|
||||||
|
var items []uint64
|
||||||
|
for i := uint16(0); i < numItems; i++ {
|
||||||
|
var item uint64
|
||||||
|
err = readElement(r, &item)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
*e = *&items
|
||||||
|
return nil
|
||||||
case *[]*btcec.Signature:
|
case *[]*btcec.Signature:
|
||||||
var numSigs uint8
|
var numSigs uint8
|
||||||
err = readElement(r, &numSigs)
|
err = readElement(r, &numSigs)
|
||||||
|
Loading…
Reference in New Issue
Block a user