|
1 | | -import { DefaultLdkDataShape, TLdkStorage } from './types'; |
| 1 | +import { |
| 2 | + DefaultLdkDataShape, |
| 3 | + ENetworks, |
| 4 | + TLdkStart, |
| 5 | + TLdkStorage, |
| 6 | +} from './types'; |
| 7 | +import { err, ok, Result } from './result'; |
2 | 8 |
|
3 | 9 | /** |
4 | 10 | * Convert string to bytes |
@@ -90,3 +96,155 @@ export const getDefaultLdkStorageShape = (seed: string): TLdkStorage => { |
90 | 96 | [seed]: DefaultLdkDataShape, |
91 | 97 | }; |
92 | 98 | }; |
| 99 | + |
| 100 | +/** |
| 101 | + * This method runs a check on each parameter passed to the start method |
| 102 | + * to ensure that they are providing the expected data. |
| 103 | + * @param {string} seed |
| 104 | + * @param {string} genesisHash |
| 105 | + * @param {TGetBestBlock} getBestBlock |
| 106 | + * @param {TStorage} getItem |
| 107 | + * @param {TStorage} setItem |
| 108 | + * @param {TGetTransactionData} getTransactionData |
| 109 | + * @param {ENetworks} network |
| 110 | + * @returns {Promise<Result<string>>} |
| 111 | + */ |
| 112 | +export const startParamCheck = async ({ |
| 113 | + seed, |
| 114 | + genesisHash, |
| 115 | + getBestBlock, |
| 116 | + getItem, |
| 117 | + setItem, |
| 118 | + getTransactionData, |
| 119 | + network = ENetworks.regtest, |
| 120 | +}: TLdkStart): Promise<Result<string>> => { |
| 121 | + try { |
| 122 | + // Test Network |
| 123 | + if (typeof network !== 'string') { |
| 124 | + return err('network must be a string.'); |
| 125 | + } |
| 126 | + if ( |
| 127 | + !( |
| 128 | + network === ENetworks.mainnet || |
| 129 | + network === ENetworks.testnet || |
| 130 | + network === ENetworks.regtest |
| 131 | + ) |
| 132 | + ) { |
| 133 | + return err( |
| 134 | + `The provided network (${network}) is invalid. It must be either '${ENetworks.mainnet}', '${ENetworks.testnet}' or '${ENetworks.regtest}'.`, |
| 135 | + ); |
| 136 | + } |
| 137 | + |
| 138 | + // Test seed |
| 139 | + if (typeof seed !== 'string') { |
| 140 | + return err('seed must be a string.'); |
| 141 | + } |
| 142 | + |
| 143 | + // Test genesisHash |
| 144 | + if (typeof genesisHash !== 'string') { |
| 145 | + return err('genesisHash must be a string.'); |
| 146 | + } |
| 147 | + if (typeof genesisHash !== 'string') { |
| 148 | + return err('genesisHash must be a string.'); |
| 149 | + } |
| 150 | + |
| 151 | + // Test getBestBlock |
| 152 | + if (!isFunction(getBestBlock)) { |
| 153 | + return err('getBestBlock must be a function.'); |
| 154 | + } |
| 155 | + const bestBlock = await getBestBlock(); |
| 156 | + if (!bestBlock?.hex || !bestBlock.height || !bestBlock.hash) { |
| 157 | + return err('getBestBlock is not providing the expected data.}'); |
| 158 | + } |
| 159 | + |
| 160 | + // Test setItem & getItem |
| 161 | + if (!isFunction(setItem)) { |
| 162 | + return err('setItem must be a function.'); |
| 163 | + } |
| 164 | + if (!isFunction(getItem)) { |
| 165 | + return err('getItem must be a function.'); |
| 166 | + } |
| 167 | + const rand = Math.random().toString(); |
| 168 | + await setItem('ldkstoragetest', rand); |
| 169 | + const getTest = await getItem('ldkstoragetest'); |
| 170 | + if (getTest !== rand) { |
| 171 | + return err('setItem & getItem are not able to access storage.'); |
| 172 | + } |
| 173 | + |
| 174 | + // Test getTransactionData |
| 175 | + if (!isFunction(getTransactionData)) { |
| 176 | + return err('getTransactionData must be a function.'); |
| 177 | + } |
| 178 | + // Test getTransactionData response if using mainnet or testnet. |
| 179 | + if (network !== ENetworks.regtest) { |
| 180 | + const expectedData = { |
| 181 | + [ENetworks.mainnet]: { |
| 182 | + txid: 'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16', |
| 183 | + data: { |
| 184 | + header: |
| 185 | + '01000000696aa63f0f22d9189c8536bb83b18737ae8336c25a67937f79957e5600000000982db9870a5e30d8f0b2a4ebccc5852b5a1e2413e9274c4947bfec6bdaa9b9d75bb76a49ffff001d2b719fdd', |
| 186 | + height: 170, |
| 187 | + transaction: |
| 188 | + '0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000', |
| 189 | + }, |
| 190 | + }, |
| 191 | + [ENetworks.testnet]: { |
| 192 | + txid: '3757bc9ac72b4aba0babe9c5ee94373c6b8c675766b7c188af4c5e75068b78e3', |
| 193 | + data: { |
| 194 | + header: |
| 195 | + '0100000098fbe05200b867e000286338ee405f70ce4362f54769db2bc9d919db0000000078b787d3d8da61dce5a9fe4d4a9232e804021e439906e6fd52cf8f041f948b3d919d4a4dffff001d05774a61', |
| 196 | + height: 420, |
| 197 | + transaction: |
| 198 | + '0100000001d604a444f1b98c382cb0557c4972d2d0050e19a570f0c9592a8afd40e6eea450000000006a47304402205df0be0956dcd01ab514a6965faabe6a0202289ef9ca16a60fb17612ba23598902202c877276bb12e5c7e27f377e926bebe3afa6629c1785a732a26df4322a83eae7012102219f426bcf9151bb514807f6c1796361a6abf6e094a2e75da0ed91f587c07b37ffffffff02302f1526010000001976a9145c7f849d51b5708ec29d38fdce2e995da069e01588ac5dfd01000000000017a914c925e02c0560da5d9cd263481347b025b8f196f48700000000', |
| 199 | + }, |
| 200 | + }, |
| 201 | + }; |
| 202 | + const transactionData = await getTransactionData( |
| 203 | + expectedData[network].txid, |
| 204 | + ); |
| 205 | + if ( |
| 206 | + JSON.stringify(transactionData) !== |
| 207 | + JSON.stringify(expectedData[network].data) |
| 208 | + ) { |
| 209 | + return err('getTransactionData is not returning the expected data.'); |
| 210 | + } |
| 211 | + } |
| 212 | + return ok('Params passed all checks.'); |
| 213 | + } catch (e) { |
| 214 | + return err(e); |
| 215 | + } |
| 216 | +}; |
| 217 | + |
| 218 | +const isFunction = (f: any): boolean => { |
| 219 | + try { |
| 220 | + return f && {}.toString.call(f) === '[object Function]'; |
| 221 | + } catch { |
| 222 | + return false; |
| 223 | + } |
| 224 | +}; |
| 225 | + |
| 226 | +const shuffle = (array: string[]): string[] => { |
| 227 | + let currentIndex = array.length, |
| 228 | + randomIndex; |
| 229 | + while (currentIndex !== 0) { |
| 230 | + randomIndex = Math.floor(Math.random() * currentIndex); |
| 231 | + currentIndex--; |
| 232 | + [array[currentIndex], array[randomIndex]] = [ |
| 233 | + array[randomIndex], |
| 234 | + array[currentIndex], |
| 235 | + ]; |
| 236 | + } |
| 237 | + |
| 238 | + return array; |
| 239 | +}; |
| 240 | + |
| 241 | +export const dummyRandomSeed = (): string => { |
| 242 | + if (!__DEV__) { |
| 243 | + throw new Error('Use random bytes instead of dummyRandomSeed'); |
| 244 | + } |
| 245 | + |
| 246 | + const bytes = |
| 247 | + '8a bd ac 77 55 2a 6e a6 0a 47 2f bf 6c d8 d5 af b4 78 19 96 a4 d2 e2 81 7c ae 6e 2b 38 ae 56 fd'; |
| 248 | + |
| 249 | + return shuffle(bytes.split(' ')).join(''); |
| 250 | +}; |
0 commit comments