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
|
||||
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.
|
||||
CommitmentHeight uint64
|
||||
|
||||
//The last staging included by both parties
|
||||
//Basically, the state is updated to this point on both parties'
|
||||
//staging
|
||||
//Staging inclusion is in order.
|
||||
CommitterLastStaging uint64
|
||||
ReceiverLastStaging uint64
|
||||
//List of HTLC Keys which are updated from all parties
|
||||
UpdatedHTLCKeys []uint64
|
||||
|
||||
//Hash of the revocation to use
|
||||
RevocationHash [20]byte
|
||||
@ -41,16 +37,14 @@ type CommitSignature struct {
|
||||
func (c *CommitSignature) Decode(r io.Reader, pver uint32) error {
|
||||
//ChannelID(8)
|
||||
//CommitmentHeight(8)
|
||||
//CommiterLastStaging(8)
|
||||
//ReceiverLastStaging(8)
|
||||
//c.UpdatedHTLCKeys(8*1000max)
|
||||
//RevocationHash(20)
|
||||
//Fee(8)
|
||||
//RequesterCommitSig(73max+2)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.CommitmentHeight,
|
||||
&c.CommitterLastStaging,
|
||||
&c.ReceiverLastStaging,
|
||||
&c.UpdatedHTLCKeys,
|
||||
&c.RevocationHash,
|
||||
&c.Fee,
|
||||
&c.CommitSig,
|
||||
@ -73,8 +67,7 @@ func (c *CommitSignature) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.CommitmentHeight,
|
||||
c.CommitterLastStaging,
|
||||
c.ReceiverLastStaging,
|
||||
c.UpdatedHTLCKeys,
|
||||
c.RevocationHash,
|
||||
c.Fee,
|
||||
c.CommitSig,
|
||||
@ -91,7 +84,7 @@ func (c *CommitSignature) Command() 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)
|
||||
@ -108,21 +101,23 @@ func (c *CommitSignature) Validate() error {
|
||||
func (c *CommitSignature) String() string {
|
||||
//c.ChannelID,
|
||||
//c.CommitmentHeight,
|
||||
//c.CommitterLastStaging,
|
||||
//c.ReceiverLastStaging,
|
||||
//c.RevocationHash,
|
||||
//c.UpdatedHTLCKeys,
|
||||
//c.Fee,
|
||||
//c.CommitSig,
|
||||
var serializedSig []byte
|
||||
if &c.CommitSig != nil && c.CommitSig.R != nil {
|
||||
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") +
|
||||
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
|
||||
fmt.Sprintf("CommitmentHeight:\t%d\n", c.CommitmentHeight) +
|
||||
fmt.Sprintf("CommitterLastStaging:\t%d\n", c.CommitterLastStaging) +
|
||||
fmt.Sprintf("ReceiverLastStaging:\t%d\n", c.ReceiverLastStaging) +
|
||||
fmt.Sprintf("UpdatedHTLCKeys:\t%s\n", items) +
|
||||
fmt.Sprintf("RevocationHash:\t\t%x\n", c.RevocationHash) +
|
||||
fmt.Sprintf("Fee:\t\t\t%s\n", c.Fee.String()) +
|
||||
fmt.Sprintf("CommitSig:\t\t%x\n", serializedSig) +
|
||||
|
@ -10,16 +10,16 @@ var (
|
||||
_ = copy(revocationHash[:], revocationHashBytes)
|
||||
|
||||
commitSignature = &CommitSignature{
|
||||
ChannelID: uint64(12345678),
|
||||
CommitmentHeight: uint64(12345),
|
||||
CommitterLastStaging: uint64(12345678),
|
||||
ReceiverLastStaging: uint64(87654321),
|
||||
RevocationHash: revocationHash,
|
||||
Fee: btcutil.Amount(10000),
|
||||
CommitSig: commitSig,
|
||||
ChannelID: uint64(12345678),
|
||||
CommitmentHeight: uint64(12345),
|
||||
//CommitterLastStaging: uint64(12345678),
|
||||
UpdatedHTLCKeys: []uint64{1, 2, 3, 4, 5},
|
||||
RevocationHash: revocationHash,
|
||||
Fee: btcutil.Amount(10000),
|
||||
CommitSig: commitSig,
|
||||
}
|
||||
commitSignatureSerializedString = "0000000000bc614e00000000000030390000000000bc614e0000000005397fb14132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
||||
commitSignatureSerializedMessage = "0709110b000007d0000000830000000000bc614e00000000000030390000000000bc614e0000000005397fb14132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
||||
commitSignatureSerializedString = "0000000000bc614e00000000000030390005000000000000000100000000000000020000000000000003000000000000000400000000000000054132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
||||
commitSignatureSerializedMessage = "0709110b000007d00000009d0000000000bc614e00000000000030390005000000000000000100000000000000020000000000000003000000000000000400000000000000054132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
|
||||
)
|
||||
|
||||
func TestCommitSignatureEncodeDecode(t *testing.T) {
|
||||
|
@ -7,18 +7,15 @@ import (
|
||||
|
||||
type HTLCAddAccept struct {
|
||||
ChannelID uint64
|
||||
StagingID uint64
|
||||
HTLCKey HTLCKey
|
||||
}
|
||||
|
||||
func (c *HTLCAddAccept) Decode(r io.Reader, pver uint32) error {
|
||||
//ChannelID(8)
|
||||
//CommitmentHeight(8)
|
||||
//NextResponderCommitmentRevocationHash(20)
|
||||
//ResponderRevocationPreimage(20)
|
||||
//ResponderCommitSig(2+73max)
|
||||
//HTLCKey(8)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.StagingID,
|
||||
&c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -37,7 +34,7 @@ func NewHTLCAddAccept() *HTLCAddAccept {
|
||||
func (c *HTLCAddAccept) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.StagingID,
|
||||
c.HTLCKey,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@ -65,6 +62,6 @@ func (c *HTLCAddAccept) Validate() error {
|
||||
func (c *HTLCAddAccept) String() string {
|
||||
return fmt.Sprintf("\n--- Begin HTLCAddAccept ---\n") +
|
||||
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")
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
var (
|
||||
htlcAddAccept = &HTLCAddAccept{
|
||||
ChannelID: uint64(12345678),
|
||||
StagingID: uint64(12345),
|
||||
HTLCKey: HTLCKey(12345),
|
||||
}
|
||||
htlcAddAcceptSerializedString = "0000000000bc614e0000000000003039"
|
||||
htlcAddAcceptSerializedMessage = "0709110b000003f2000000100000000000bc614e0000000000003039"
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
type HTLCAddReject struct {
|
||||
ChannelID uint64
|
||||
StagingID uint64
|
||||
HTLCKey HTLCKey
|
||||
}
|
||||
|
||||
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)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.StagingID,
|
||||
&c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -37,7 +37,7 @@ func NewHTLCAddReject() *HTLCAddReject {
|
||||
func (c *HTLCAddReject) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.StagingID,
|
||||
c.HTLCKey,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@ -65,6 +65,6 @@ func (c *HTLCAddReject) Validate() error {
|
||||
func (c *HTLCAddReject) String() string {
|
||||
return fmt.Sprintf("\n--- Begin HTLCAddReject ---\n") +
|
||||
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")
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
var (
|
||||
htlcAddReject = &HTLCAddReject{
|
||||
ChannelID: uint64(12345678),
|
||||
StagingID: uint64(12345),
|
||||
HTLCKey: HTLCKey(12345),
|
||||
}
|
||||
htlcAddRejectSerializedString = "0000000000bc614e0000000000003039"
|
||||
htlcAddRejectSerializedMessage = "0709110b000003fc000000100000000000bc614e0000000000003039"
|
||||
|
@ -12,7 +12,7 @@ type HTLCAddRequest struct {
|
||||
ChannelID uint64
|
||||
|
||||
//ID of this request
|
||||
StagingID uint64
|
||||
HTLCKey HTLCKey
|
||||
|
||||
//When the HTLC expires
|
||||
Expiry uint32
|
||||
@ -21,8 +21,9 @@ type HTLCAddRequest struct {
|
||||
//Difference between hop and first item in blob is the fee to complete
|
||||
Amount CreditsAmount
|
||||
|
||||
//Hash160 address of the next hop.
|
||||
NextHop [20]byte
|
||||
//RefundContext is for payment cancellation
|
||||
//TODO (j): not currently in use, add later
|
||||
RefundContext HTLCKey
|
||||
|
||||
//Contract Type
|
||||
//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 {
|
||||
//ChannelID(8)
|
||||
//StagingID(8)
|
||||
//HTLCKey(8)
|
||||
//Expiry(4)
|
||||
//Amount(4)
|
||||
//NextHop(20)
|
||||
//ContractType(1)
|
||||
//RedemptionHashes (numOfHashes * 20 + numOfHashes)
|
||||
//Blob(2+blobsize)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.StagingID,
|
||||
&c.HTLCKey,
|
||||
&c.Expiry,
|
||||
&c.Amount,
|
||||
&c.NextHop,
|
||||
&c.ContractType,
|
||||
&c.RedemptionHashes,
|
||||
&c.Blob,
|
||||
@ -72,10 +71,9 @@ func NewHTLCAddRequest() *HTLCAddRequest {
|
||||
func (c *HTLCAddRequest) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.StagingID,
|
||||
c.HTLCKey,
|
||||
c.Expiry,
|
||||
c.Amount,
|
||||
c.NextHop,
|
||||
c.ContractType,
|
||||
c.RedemptionHashes,
|
||||
c.Blob,
|
||||
@ -117,10 +115,9 @@ func (c *HTLCAddRequest) String() string {
|
||||
|
||||
return fmt.Sprintf("\n--- Begin HTLCAddRequest ---\n") +
|
||||
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("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("RedemptionHashes:") +
|
||||
redemptionHashes +
|
||||
|
@ -8,23 +8,21 @@ var (
|
||||
//Need to to do this here
|
||||
_ = copy(revocationHash[:], revocationHashBytes)
|
||||
_ = copy(redemptionHash[:], redemptionHashBytes)
|
||||
_ = copy(nextHop[:], nextHopBytes)
|
||||
emptyRedemptionHashes = []*[20]byte{}
|
||||
redemptionHashes = append(emptyRedemptionHashes, &redemptionHash)
|
||||
|
||||
htlcAddRequest = &HTLCAddRequest{
|
||||
ChannelID: uint64(12345678),
|
||||
StagingID: uint64(12345),
|
||||
HTLCKey: HTLCKey(12345),
|
||||
Expiry: uint32(144),
|
||||
Amount: CreditsAmount(123456000),
|
||||
NextHop: nextHop,
|
||||
ContractType: uint8(17),
|
||||
RedemptionHashes: redemptionHashes,
|
||||
|
||||
Blob: []byte{255, 0, 255, 0, 255, 0, 255, 0},
|
||||
}
|
||||
htlcAddRequestSerializedString = "0000000000bc614e000000000000303900000090075bca0094a9ded5a30fc5944cb1e2cbcd980f30616a14401100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
||||
htlcAddRequestSerializedMessage = "0709110b000003e80000004d0000000000bc614e000000000000303900000090075bca0094a9ded5a30fc5944cb1e2cbcd980f30616a14401100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
||||
htlcAddRequestSerializedString = "0000000000bc614e000000000000303900000090075bca001100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
||||
htlcAddRequestSerializedMessage = "0709110b000003e8000000390000000000bc614e000000000000303900000090075bca001100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"
|
||||
)
|
||||
|
||||
func TestHTLCAddRequestEncodeDecode(t *testing.T) {
|
||||
|
@ -12,15 +12,15 @@ type HTLCSettleAccept struct {
|
||||
ChannelID uint64
|
||||
|
||||
//ID of this request
|
||||
StagingID uint64
|
||||
HTLCKey HTLCKey
|
||||
}
|
||||
|
||||
func (c *HTLCSettleAccept) Decode(r io.Reader, pver uint32) error {
|
||||
//ChannelID(8)
|
||||
//StagingID(8)
|
||||
//HTLCKey(8)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.StagingID,
|
||||
&c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -39,7 +39,7 @@ func NewHTLCSettleAccept() *HTLCSettleAccept {
|
||||
func (c *HTLCSettleAccept) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.StagingID,
|
||||
c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -66,6 +66,6 @@ func (c *HTLCSettleAccept) Validate() error {
|
||||
func (c *HTLCSettleAccept) String() string {
|
||||
return fmt.Sprintf("\n--- Begin HTLCSettleAccept ---\n") +
|
||||
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")
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
var (
|
||||
htlcSettleAccept = &HTLCSettleAccept{
|
||||
ChannelID: uint64(12345678),
|
||||
StagingID: uint64(12345),
|
||||
HTLCKey: HTLCKey(12345),
|
||||
}
|
||||
htlcSettleAcceptSerializedString = "0000000000bc614e0000000000003039"
|
||||
htlcSettleAcceptSerializedMessage = "0709110b00000456000000100000000000bc614e0000000000003039"
|
||||
|
@ -12,7 +12,7 @@ type HTLCSettleRequest struct {
|
||||
ChannelID uint64
|
||||
|
||||
//ID of this request
|
||||
StagingID uint64
|
||||
HTLCKey HTLCKey
|
||||
|
||||
//Redemption Proofs (R-Values)
|
||||
RedemptionProofs []*[20]byte
|
||||
@ -20,7 +20,7 @@ type HTLCSettleRequest struct {
|
||||
|
||||
func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
|
||||
//ChannelID(8)
|
||||
//StagingID(8)
|
||||
//HTLCKey(8)
|
||||
//Expiry(4)
|
||||
//Amount(4)
|
||||
//NextHop(20)
|
||||
@ -29,7 +29,7 @@ func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
|
||||
//Blob(2+blobsize)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.StagingID,
|
||||
&c.HTLCKey,
|
||||
&c.RedemptionProofs,
|
||||
)
|
||||
if err != nil {
|
||||
@ -49,7 +49,7 @@ func NewHTLCSettleRequest() *HTLCSettleRequest {
|
||||
func (c *HTLCSettleRequest) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.StagingID,
|
||||
c.HTLCKey,
|
||||
c.RedemptionProofs,
|
||||
)
|
||||
if err != nil {
|
||||
@ -83,7 +83,7 @@ func (c *HTLCSettleRequest) String() string {
|
||||
|
||||
return fmt.Sprintf("\n--- Begin HTLCSettleRequest ---\n") +
|
||||
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:") +
|
||||
redemptionProofs +
|
||||
fmt.Sprintf("--- End HTLCSettleRequest ---\n")
|
||||
|
@ -12,7 +12,7 @@ var (
|
||||
|
||||
htlcSettleRequest = &HTLCSettleRequest{
|
||||
ChannelID: uint64(12345678),
|
||||
StagingID: uint64(12345),
|
||||
HTLCKey: HTLCKey(12345),
|
||||
RedemptionProofs: redemptionProofs,
|
||||
}
|
||||
htlcSettleRequestSerializedString = "0000000000bc614e000000000000303900015b315ebabb0d8c0d94281caa2dfee69a1a00436e"
|
||||
|
@ -12,15 +12,15 @@ type HTLCTimeoutAccept struct {
|
||||
ChannelID uint64
|
||||
|
||||
//ID of this request
|
||||
StagingID uint64
|
||||
HTLCKey HTLCKey
|
||||
}
|
||||
|
||||
func (c *HTLCTimeoutAccept) Decode(r io.Reader, pver uint32) error {
|
||||
//ChannelID(8)
|
||||
//StagingID(8)
|
||||
//HTLCKey(8)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.StagingID,
|
||||
&c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -39,7 +39,7 @@ func NewHTLCTimeoutAccept() *HTLCTimeoutAccept {
|
||||
func (c *HTLCTimeoutAccept) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.StagingID,
|
||||
c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -66,6 +66,6 @@ func (c *HTLCTimeoutAccept) Validate() error {
|
||||
func (c *HTLCTimeoutAccept) String() string {
|
||||
return fmt.Sprintf("\n--- Begin HTLCTimeoutAccept ---\n") +
|
||||
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")
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
var (
|
||||
htlcTimeoutAccept = &HTLCTimeoutAccept{
|
||||
ChannelID: uint64(12345678),
|
||||
StagingID: uint64(12345),
|
||||
HTLCKey: HTLCKey(12345),
|
||||
}
|
||||
htlcTimeoutAcceptSerializedString = "0000000000bc614e0000000000003039"
|
||||
htlcTimeoutAcceptSerializedMessage = "0709110b0000051e000000100000000000bc614e0000000000003039"
|
||||
|
@ -12,15 +12,15 @@ type HTLCTimeoutRequest struct {
|
||||
ChannelID uint64
|
||||
|
||||
//ID of this request
|
||||
StagingID uint64
|
||||
HTLCKey HTLCKey
|
||||
}
|
||||
|
||||
func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error {
|
||||
//ChannelID(8)
|
||||
//StagingID(8)
|
||||
//HTLCKey(8)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.StagingID,
|
||||
&c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -39,7 +39,7 @@ func NewHTLCTimeoutRequest() *HTLCTimeoutRequest {
|
||||
func (c *HTLCTimeoutRequest) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.StagingID,
|
||||
c.HTLCKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -66,6 +66,6 @@ func (c *HTLCTimeoutRequest) Validate() error {
|
||||
func (c *HTLCTimeoutRequest) String() string {
|
||||
return fmt.Sprintf("\n--- Begin HTLCTimeoutRequest ---\n") +
|
||||
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")
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
var (
|
||||
htlcTimeoutRequest = &HTLCTimeoutRequest{
|
||||
ChannelID: uint64(12345678),
|
||||
StagingID: uint64(12345),
|
||||
HTLCKey: HTLCKey(12345),
|
||||
}
|
||||
htlcTimeoutRequestSerializedString = "0000000000bc614e0000000000003039"
|
||||
htlcTimeoutRequestSerializedMessage = "0709110b00000514000000100000000000bc614e0000000000003039"
|
||||
|
@ -16,6 +16,9 @@ var MAX_SLICE_LENGTH = 65535
|
||||
//Actual pkScript, not redeemScript
|
||||
type PkScript []byte
|
||||
|
||||
type HTLCKey uint64
|
||||
type CommitHeight uint64
|
||||
|
||||
//Subsatoshi amount (Micro-Satoshi, 1/1000th)
|
||||
//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 nil
|
||||
case HTLCKey:
|
||||
err = writeElement(w, uint64(e))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case btcutil.Amount:
|
||||
err = binary.Write(w, binary.BigEndian, int64(e))
|
||||
if err != nil {
|
||||
@ -94,6 +102,24 @@ func writeElement(w io.Writer, element interface{}) error {
|
||||
return err
|
||||
}
|
||||
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:
|
||||
numSigs := len(e)
|
||||
if numSigs > 127 {
|
||||
@ -313,6 +339,14 @@ func readElement(r io.Reader, element interface{}) error {
|
||||
}
|
||||
*e = binary.BigEndian.Uint64(b[:])
|
||||
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:
|
||||
var b [8]byte
|
||||
_, err = io.ReadFull(r, b[:])
|
||||
@ -341,6 +375,28 @@ func readElement(r io.Reader, element interface{}) error {
|
||||
}
|
||||
*e = &*x
|
||||
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:
|
||||
var numSigs uint8
|
||||
err = readElement(r, &numSigs)
|
||||
|
Loading…
Reference in New Issue
Block a user