From 04d0e099cc50bf2893908c8e0edb1a8e83476be5 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 2 May 2017 19:16:37 -0700 Subject: [PATCH] lnd: add new chainRegistry struct for multi-chain dispatch This commit adds a new agent to the codebase: the chainRegistry. In a multi-chain future, the chainRegistry will be the dispatch point capable of mapping cross-chain parameters, and a particular chain to the chainControl for that chain. The chainControl struct encompasses the 3 primary interfaces used within the daemon to register for events, and drive other workflows. --- chainregistry.go | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 chainregistry.go diff --git a/chainregistry.go b/chainregistry.go new file mode 100644 index 00000000..fce16ab3 --- /dev/null +++ b/chainregistry.go @@ -0,0 +1,164 @@ +package main + +import ( + "sync" + + "github.com/lightningnetwork/lnd/chainntnfs" + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/roasbeef/btcd/chaincfg/chainhash" +) + +// chainCode is an enum-like structure for keeping track of the chains currently +// supported within lnd. +type chainCode uint32 + +const ( + // bitcoinChain is Bitcoin's testnet chain. + bitcoinChain chainCode = iota + + // litecoinChain is Litecoin's testnet chain. + litecoinChain +) + +// String returns a string representation of the target chainCode. +func (c chainCode) String() string { + switch c { + case bitcoinChain: + return "bitcoin" + case litecoinChain: + return "litecoin" + default: + return "kekcoin" + } +} + +// chainControl couples the three primary interfaces lnd utilizes for a +// particular chain together. A single chainControl instance will exist for all +// the chains lnd is currently active on. +type chainControl struct { + chainIO lnwallet.BlockChainIO + chainNotifier chainntnfs.ChainNotifier + + wallet *lnwallet.LightningWallet +} + +var ( + // bitcoinGenesis is the genesis hash of Bitcoin's testnet chain. + bitcoinGenesis = chainhash.Hash([chainhash.HashSize]byte{ + 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, + 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, + 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, + 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, + }) + + // litecoinGenesis is the genesis hash of Litecoin's testnet4 chain. + litecoinGenesis = chainhash.Hash([chainhash.HashSize]byte{ + 0xa0, 0x29, 0x3e, 0x4e, 0xeb, 0x3d, 0xa6, 0xe6, + 0xf5, 0x6f, 0x81, 0xed, 0x59, 0x5f, 0x57, 0x88, + 0x0d, 0x1a, 0x21, 0x56, 0x9e, 0x13, 0xee, 0xfd, + 0xd9, 0x51, 0x28, 0x4b, 0x5a, 0x62, 0x66, 0x49, + }) + + // chainMap is a simple index that maps a chain's genesis hash to the + // chainCode enum for that chain. + chainMap = map[chainhash.Hash]chainCode{ + bitcoinGenesis: bitcoinChain, + litecoinGenesis: litecoinChain, + } + + // reverseChainMap is the inverse of the chainMap above: it maps the + // chain enum for a chain to its genesis hash. + reverseChainMap = map[chainCode]chainhash.Hash{ + bitcoinChain: bitcoinGenesis, + litecoinChain: litecoinGenesis, + } +) + +// chainRegistry keeps track of the current chains +type chainRegistry struct { + sync.RWMutex + + activeChains map[chainCode]*chainControl + netParams map[chainCode]*bitcoinNetParams + + primaryChain chainCode +} + +// newChainRegistry creates a new chainRegistry. +func newChainRegistry() *chainRegistry { + return &chainRegistry{ + activeChains: make(map[chainCode]*chainControl), + netParams: make(map[chainCode]*bitcoinNetParams), + } +} + +// RegisterChain assigns an active chainControl instance to a target chain +// identified by its chainCode. +func (c *chainRegistry) RegisterChain(newChain chainCode, cc *chainControl) { + c.Lock() + c.activeChains[newChain] = cc + c.Unlock() +} + +// LookupChain attempts to lookup an active chainControl instance for the +// target chain. +func (c *chainRegistry) LookupChain(targetChain chainCode) (*chainControl, bool) { + c.RLock() + cc, ok := c.activeChains[targetChain] + c.RUnlock() + return cc, ok +} + +// LookupChainByHash attempts to look up an active chainControl which +// corresponds to the passed genesis hash. +func (c *chainRegistry) LookupChainByHash(chainHash chainhash.Hash) (*chainControl, bool) { + c.RLock() + defer c.RUnlock() + + targetChain, ok := chainMap[chainHash] + if !ok { + return nil, ok + } + + cc, ok := c.activeChains[targetChain] + return cc, ok +} + +// RegisterPrimaryChain sets a target chain as the "home chain" for lnd. +func (c *chainRegistry) RegisterPrimaryChain(cc chainCode) { + c.Lock() + defer c.Unlock() + + c.primaryChain = cc +} + +// PrimaryChain returns the primary chain for this running lnd instance. The +// primary chain is considered the "home base" while the other registered +// chains are treated as secondary chains. +func (c *chainRegistry) PrimaryChain() chainCode { + c.RLock() + defer c.RUnlock() + + return c.primaryChain +} + +// ActiveChains returns the total number of active chains. +func (c *chainRegistry) ActiveChains() []chainCode { + c.RLock() + defer c.RUnlock() + + chains := make([]chainCode, 0, len(c.activeChains)) + for activeChain := range c.activeChains { + chains = append(chains, activeChain) + } + + return chains +} + +// NumActiveChains returns the total number of active chains. +func (c *chainRegistry) NumActiveChains() uint32 { + c.RLock() + defer c.RUnlock() + + return uint32(len(c.activeChains)) +}