htlcswitch/circuit_map: add Config and Reextract obfuscators

This commit is contained in:
Conner Fromknecht 2018-03-12 12:47:56 -07:00
parent 4ced071a7d
commit 64ee4e0247
No known key found for this signature in database
GPG Key ID: 39DE78FBE6ACB0EF
1 changed files with 42 additions and 17 deletions

View File

@ -144,11 +144,7 @@ var (
// always identifiable by their incoming CircuitKey, in addition to their // always identifiable by their incoming CircuitKey, in addition to their
// outgoing CircuitKey if the circuit is fully-opened. // outgoing CircuitKey if the circuit is fully-opened.
type circuitMap struct { type circuitMap struct {
// db provides the persistent storage engine for the circuit map. cfg *CircuitMapConfig
//
// TODO(conner): create abstraction to allow for the substitution of
// other persistence engines.
db *channeldb.DB
mtx sync.RWMutex mtx sync.RWMutex
@ -172,10 +168,23 @@ type circuitMap struct {
hashIndex map[[32]byte]map[CircuitKey]struct{} hashIndex map[[32]byte]map[CircuitKey]struct{}
} }
// CircuitMapConfig houses the critical interfaces and references necessary to
// parameterize an instance of circuitMap.
type CircuitMapConfig struct {
// DB provides the persistent storage engine for the circuit map.
// TODO(conner): create abstraction to allow for the substitution of
// other persistence engines.
DB *channeldb.DB
// ExtractErrorEncrypter derives the shared secret used to encrypt
// errors from the obfuscator's ephemeral public key.
ExtractErrorEncrypter ErrorEncrypterExtracter
}
// NewCircuitMap creates a new instance of the circuitMap. // NewCircuitMap creates a new instance of the circuitMap.
func NewCircuitMap(db *channeldb.DB) (CircuitMap, error) { func NewCircuitMap(cfg *CircuitMapConfig) (CircuitMap, error) {
cm := &circuitMap{ cm := &circuitMap{
db: db, cfg: cfg,
} }
// Initialize the on-disk buckets used by the circuit map. // Initialize the on-disk buckets used by the circuit map.
@ -203,7 +212,7 @@ func NewCircuitMap(db *channeldb.DB) (CircuitMap, error) {
// initBuckets ensures that the primary buckets used by the circuit are // initBuckets ensures that the primary buckets used by the circuit are
// initialized so that we can assume their existence after startup. // initialized so that we can assume their existence after startup.
func (cm *circuitMap) initBuckets() error { func (cm *circuitMap) initBuckets() error {
return cm.db.Update(func(tx *bolt.Tx) error { return cm.cfg.DB.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(circuitKeystoneKey) _, err := tx.CreateBucketIfNotExists(circuitKeystoneKey)
if err != nil { if err != nil {
return err return err
@ -226,7 +235,7 @@ func (cm *circuitMap) restoreMemState() error {
pending = make(map[CircuitKey]*PaymentCircuit) pending = make(map[CircuitKey]*PaymentCircuit)
) )
if err := cm.db.View(func(tx *bolt.Tx) error { if err := cm.cfg.DB.View(func(tx *bolt.Tx) error {
// Restore any of the circuits persisted in the circuit bucket // Restore any of the circuits persisted in the circuit bucket
// back into memory. // back into memory.
circuitBkt := tx.Bucket(circuitAddKey) circuitBkt := tx.Bucket(circuitAddKey)
@ -235,7 +244,7 @@ func (cm *circuitMap) restoreMemState() error {
} }
if err := circuitBkt.ForEach(func(_, v []byte) error { if err := circuitBkt.ForEach(func(_, v []byte) error {
circuit, err := decodeCircuit(v) circuit, err := cm.decodeCircuit(v)
if err != nil { if err != nil {
return err return err
} }
@ -305,8 +314,9 @@ func (cm *circuitMap) restoreMemState() error {
// decodeCircuit reconstructs an in-memory payment circuit from a byte slice. // decodeCircuit reconstructs an in-memory payment circuit from a byte slice.
// The byte slice is assumed to have been generated by the circuit's Encode // The byte slice is assumed to have been generated by the circuit's Encode
// method. // method. If the decoding is successful, the onion obfuscator will be
func decodeCircuit(v []byte) (*PaymentCircuit, error) { // reextracted, since it is not stored in plaintext on disk.
func (cm *circuitMap) decodeCircuit(v []byte) (*PaymentCircuit, error) {
var circuit = &PaymentCircuit{} var circuit = &PaymentCircuit{}
circuitReader := bytes.NewReader(v) circuitReader := bytes.NewReader(v)
@ -314,6 +324,21 @@ func decodeCircuit(v []byte) (*PaymentCircuit, error) {
return nil, err return nil, err
} }
// If the error encrypter is nil, this is locally-source payment so
// there is no encrypter.
if circuit.ErrorEncrypter == nil {
return circuit, nil
}
// Otherwise, we need to reextract the encrypter, so that the shared
// secret is rederived from what was decoded.
err := circuit.ErrorEncrypter.Reextract(
cm.cfg.ExtractErrorEncrypter,
)
if err != nil {
return nil, err
}
return circuit, nil return circuit, nil
} }
@ -325,7 +350,7 @@ func decodeCircuit(v []byte) (*PaymentCircuit, error) {
// channels. Therefore, it must be called before any links are created to avoid // channels. Therefore, it must be called before any links are created to avoid
// interfering with normal operation. // interfering with normal operation.
func (cm *circuitMap) trimAllOpenCircuits() error { func (cm *circuitMap) trimAllOpenCircuits() error {
activeChannels, err := cm.db.FetchAllChannels() activeChannels, err := cm.cfg.DB.FetchAllChannels()
if err != nil { if err != nil {
return err return err
} }
@ -385,7 +410,7 @@ func (cm *circuitMap) TrimOpenCircuits(chanID lnwire.ShortChannelID,
return nil return nil
} }
return cm.db.Update(func(tx *bolt.Tx) error { return cm.cfg.DB.Update(func(tx *bolt.Tx) error {
keystoneBkt := tx.Bucket(circuitKeystoneKey) keystoneBkt := tx.Bucket(circuitKeystoneKey)
if keystoneBkt == nil { if keystoneBkt == nil {
return ErrCorruptedCircuitMap return ErrCorruptedCircuitMap
@ -533,7 +558,7 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
// Write the entire batch of circuits to the persistent circuit bucket // Write the entire batch of circuits to the persistent circuit bucket
// using bolt's Batch write. This method must be called from multiple, // using bolt's Batch write. This method must be called from multiple,
// distinct goroutines to have any impact on performance. // distinct goroutines to have any impact on performance.
err := cm.db.Batch(func(tx *bolt.Tx) error { err := cm.cfg.DB.Batch(func(tx *bolt.Tx) error {
circuitBkt := tx.Bucket(circuitAddKey) circuitBkt := tx.Bucket(circuitAddKey)
if circuitBkt == nil { if circuitBkt == nil {
return ErrCorruptedCircuitMap return ErrCorruptedCircuitMap
@ -623,7 +648,7 @@ func (cm *circuitMap) OpenCircuits(keystones ...Keystone) error {
} }
cm.mtx.RUnlock() cm.mtx.RUnlock()
err := cm.db.Update(func(tx *bolt.Tx) error { err := cm.cfg.DB.Update(func(tx *bolt.Tx) error {
// Now, load the circuit bucket to which we will write the // Now, load the circuit bucket to which we will write the
// already serialized circuit. // already serialized circuit.
keystoneBkt := tx.Bucket(circuitKeystoneKey) keystoneBkt := tx.Bucket(circuitKeystoneKey)
@ -769,7 +794,7 @@ func (cm *circuitMap) DeleteCircuits(inKeys ...CircuitKey) error {
} }
cm.mtx.Unlock() cm.mtx.Unlock()
err := cm.db.Batch(func(tx *bolt.Tx) error { err := cm.cfg.DB.Batch(func(tx *bolt.Tx) error {
for _, circuit := range removedCircuits { for _, circuit := range removedCircuits {
// If this htlc made it to an outgoing link, load the // If this htlc made it to an outgoing link, load the
// keystone bucket from which we will remove the // keystone bucket from which we will remove the