github.com/koko1123/flow-go-1@v0.29.6/model/flow/chain.go (about) 1 package flow 2 3 import ( 4 "fmt" 5 6 "github.com/pkg/errors" 7 8 "github.com/koko1123/flow-go-1/utils/slices" 9 ) 10 11 // A ChainID is a unique identifier for a specific Flow network instance. 12 // 13 // Chain IDs are used used to prevent replay attacks and to support network-specific address generation. 14 type ChainID string 15 16 const ( 17 // Mainnet is the chain ID for the mainnet chain. 18 Mainnet ChainID = "flow-mainnet" 19 20 // Long-lived test networks 21 22 // Testnet is the chain ID for the testnet chain. 23 Testnet ChainID = "flow-testnet" 24 // Sandboxnet is the chain ID for internal sandboxnet chain. 25 Sandboxnet ChainID = "flow-sandboxnet" 26 27 // Transient test networks 28 29 // Benchnet is the chain ID for the transient benchmarking chain. 30 Benchnet ChainID = "flow-benchnet" 31 // Localnet is the chain ID for the local development chain. 32 Localnet ChainID = "flow-localnet" 33 // Emulator is the chain ID for the emulated chain. 34 Emulator ChainID = "flow-emulator" 35 // BftTestnet is the chain ID for testing attack vector scenarios. 36 BftTestnet ChainID = "flow-bft-test-net" 37 38 // MonotonicEmulator is the chain ID for the emulated node chain with monotonic address generation. 39 MonotonicEmulator ChainID = "flow-emulator-monotonic" 40 ) 41 42 // Transient returns whether the chain ID is for a transient network. 43 func (c ChainID) Transient() bool { 44 return c == Emulator || c == Localnet || c == Benchnet || c == BftTestnet 45 } 46 47 // getChainCodeWord derives the network type used for address generation from the globally 48 // configured chain ID. 49 func (c ChainID) getChainCodeWord() uint64 { 50 switch c { 51 case Mainnet: 52 return 0 53 case Testnet: 54 return invalidCodeTestNetwork 55 case Sandboxnet: 56 return invalidCodeSandboxNetwork 57 case Emulator, Localnet, Benchnet, BftTestnet: 58 return invalidCodeTransientNetwork 59 default: 60 panic(fmt.Sprintf("chain ID [%s] is invalid or does not support linear code address generation", c)) 61 } 62 } 63 64 type chainImpl interface { 65 newAddressGeneratorAtIndex(index uint64) AddressGenerator 66 // IsValid returns true if a given address is a valid account address on a given chain, 67 // and false otherwise. 68 // 69 // This is an off-chain check that only tells whether the address format is 70 // valid. If the function returns true, this does not mean 71 // a Flow account with this address has been generated. Such a test would 72 // require an on-chain check. 73 // zeroAddress() fails the check. Although it has a valid format, no account 74 // in Flow is assigned to zeroAddress(). 75 IsValid(address Address) bool 76 // IndexFromAddress extracts the index used to generate the given address 77 IndexFromAddress(address Address) (uint64, error) 78 chain() ChainID 79 } 80 81 // monotonicImpl is a simple implementation of adress generation 82 // where addresses are simply the index of the account. 83 type monotonicImpl struct{} 84 85 func (m *monotonicImpl) newAddressGeneratorAtIndex(index uint64) AddressGenerator { 86 return &MonotonicAddressGenerator{ 87 index: index, 88 } 89 } 90 91 // IsValid checks the validity of an address 92 func (m *monotonicImpl) IsValid(address Address) bool { 93 return address.uint64() > 0 && address.uint64() <= maxIndex 94 } 95 96 // IndexFromAddress returns the index used to generate the address 97 func (m *monotonicImpl) IndexFromAddress(address Address) (uint64, error) { 98 if !m.IsValid(address) { 99 return 0, errors.New("address is invalid") 100 } 101 return address.uint64(), nil 102 } 103 104 func (m *monotonicImpl) chain() ChainID { 105 return MonotonicEmulator 106 } 107 108 // linearCodeImpl is an implementation of the address generation 109 // using linear codes. 110 type linearCodeImpl struct { 111 chainID ChainID 112 } 113 114 func (l *linearCodeImpl) newAddressGeneratorAtIndex(index uint64) AddressGenerator { 115 return &linearCodeAddressGenerator{ 116 index: index, 117 chainCodeWord: l.chainID.getChainCodeWord(), 118 } 119 } 120 121 // IsValid checks the validity of an address 122 func (l *linearCodeImpl) IsValid(address Address) bool { 123 codeWord := address.uint64() 124 codeWord ^= uint64(l.chainID.getChainCodeWord()) 125 126 // zero is not a valid address 127 if codeWord == 0 { 128 return false 129 } 130 // check if address is a valid codeWord 131 return isValidCodeWord(codeWord) 132 } 133 134 // IndexFromAddress returns the index used to generate the address. 135 // It returns an error if the input is not a valid address. 136 func (l *linearCodeImpl) IndexFromAddress(address Address) (uint64, error) { 137 codeWord := address.uint64() 138 codeWord ^= uint64(l.chainID.getChainCodeWord()) 139 140 // zero is not a valid address 141 if codeWord == 0 { 142 return 0, errors.New("address is invalid") 143 } 144 145 // check the address is valid code word 146 if !isValidCodeWord(codeWord) { 147 return 0, errors.New("address is invalid") 148 } 149 return decodeCodeWord(codeWord), nil 150 } 151 152 func (l *linearCodeImpl) chain() ChainID { 153 return l.chainID 154 } 155 156 type addressedChain struct { 157 chainImpl 158 } 159 160 var mainnet = &addressedChain{ 161 chainImpl: &linearCodeImpl{ 162 chainID: Mainnet, 163 }, 164 } 165 166 var testnet = &addressedChain{ 167 chainImpl: &linearCodeImpl{ 168 chainID: Testnet, 169 }, 170 } 171 172 var bftTestNet = &addressedChain{ 173 chainImpl: &linearCodeImpl{ 174 chainID: BftTestnet, 175 }, 176 } 177 178 var sandboxnet = &addressedChain{ 179 chainImpl: &linearCodeImpl{ 180 chainID: Sandboxnet, 181 }, 182 } 183 184 var benchnet = &addressedChain{ 185 chainImpl: &linearCodeImpl{ 186 chainID: Benchnet, 187 }, 188 } 189 190 var localnet = &addressedChain{ 191 chainImpl: &linearCodeImpl{ 192 chainID: Localnet, 193 }, 194 } 195 196 var emulator = &addressedChain{ 197 chainImpl: &linearCodeImpl{ 198 chainID: Emulator, 199 }, 200 } 201 202 var monotonicEmulator = &addressedChain{ 203 chainImpl: &monotonicImpl{}, 204 } 205 206 // Chain returns the Chain corresponding to the string input 207 func (c ChainID) Chain() Chain { 208 switch c { 209 case Mainnet: 210 return mainnet 211 case Testnet: 212 return testnet 213 case Sandboxnet: 214 return sandboxnet 215 case Benchnet: 216 return benchnet 217 case Localnet: 218 return localnet 219 case Emulator: 220 return emulator 221 case MonotonicEmulator: 222 return monotonicEmulator 223 case BftTestnet: 224 return bftTestNet 225 default: 226 panic(fmt.Sprintf("chain ID [%s] is invalid ", c)) 227 } 228 } 229 230 func (c ChainID) String() string { 231 return string(c) 232 } 233 234 // Chain is the interface for address generation implementations. 235 type Chain interface { 236 NewAddressGenerator() AddressGenerator 237 AddressAtIndex(index uint64) (Address, error) 238 ServiceAddress() Address 239 BytesToAddressGenerator(b []byte) AddressGenerator 240 IsValid(Address) bool 241 IndexFromAddress(address Address) (uint64, error) 242 String() string 243 ChainID() ChainID 244 // required for tests 245 zeroAddress() Address 246 newAddressGeneratorAtIndex(index uint64) AddressGenerator 247 } 248 249 // NewAddressGenerator returns a new AddressGenerator with an 250 // initialized index. 251 func (id *addressedChain) NewAddressGenerator() AddressGenerator { 252 return id.newAddressGeneratorAtIndex(0) 253 } 254 255 // AddressAtIndex returns the index-th generated account address. 256 func (id *addressedChain) AddressAtIndex(index uint64) (Address, error) { 257 if index > maxIndex { 258 return EmptyAddress, fmt.Errorf("index must be less or equal to %x", maxIndex) 259 } 260 return id.newAddressGeneratorAtIndex(index).CurrentAddress(), nil 261 } 262 263 // ServiceAddress returns the root (first) generated account address. 264 func (id *addressedChain) ServiceAddress() Address { 265 // returned error is guaranteed to be nil 266 address, _ := id.AddressAtIndex(1) 267 return address 268 } 269 270 // zeroAddress returns the "zero address" (account that no one owns). 271 func (id *addressedChain) zeroAddress() Address { 272 // returned error is guaranteed to be nil 273 address, _ := id.AddressAtIndex(0) 274 return address 275 } 276 277 // BytesToAddressGenerator converts an array of bytes into an address index 278 func (id *addressedChain) BytesToAddressGenerator(b []byte) AddressGenerator { 279 bytes := slices.EnsureByteSliceSize(b, addressIndexLength) 280 281 index := uint48(bytes[:]) 282 return id.newAddressGeneratorAtIndex(index) 283 } 284 285 // ChainID returns the chain ID of the chain. 286 func (id *addressedChain) ChainID() ChainID { 287 return id.chain() 288 } 289 290 func (id *addressedChain) String() string { 291 return string(id.chain()) 292 }