@audius/sdk 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/.eslintrc +38 -0
  2. package/.prettierrc.js +1 -0
  3. package/.python-version +1 -0
  4. package/Dockerfile +15 -0
  5. package/README.md +3 -0
  6. package/babel.config.js +3 -0
  7. package/data-contracts/ABIs/AdminUpgradeabilityProxy.json +132 -0
  8. package/data-contracts/ABIs/BaseAdminUpgradeabilityProxy.json +113 -0
  9. package/data-contracts/ABIs/BaseUpgradeabilityProxy.json +22 -0
  10. package/data-contracts/ABIs/DiscoveryProviderFactory.json +189 -0
  11. package/data-contracts/ABIs/DiscoveryProviderFactoryInterface.json +61 -0
  12. package/data-contracts/ABIs/DiscoveryProviderStorage.json +205 -0
  13. package/data-contracts/ABIs/DiscoveryProviderStorageInterface.json +65 -0
  14. package/data-contracts/ABIs/ECDSA.json +4 -0
  15. package/data-contracts/ABIs/IPLDBlacklistFactory.json +168 -0
  16. package/data-contracts/ABIs/Initializable.json +4 -0
  17. package/data-contracts/ABIs/Migrations.json +67 -0
  18. package/data-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  19. package/data-contracts/ABIs/Ownable.json +79 -0
  20. package/data-contracts/ABIs/PlaylistFactory.json +669 -0
  21. package/data-contracts/ABIs/PlaylistFactoryInterface.json +42 -0
  22. package/data-contracts/ABIs/PlaylistStorage.json +250 -0
  23. package/data-contracts/ABIs/PlaylistStorageInterface.json +129 -0
  24. package/data-contracts/ABIs/Proxy.json +10 -0
  25. package/data-contracts/ABIs/Registry.json +240 -0
  26. package/data-contracts/ABIs/RegistryContract.json +102 -0
  27. package/data-contracts/ABIs/RegistryContractInterface.json +28 -0
  28. package/data-contracts/ABIs/RegistryInterface.json +66 -0
  29. package/data-contracts/ABIs/SigningLogic.json +43 -0
  30. package/data-contracts/ABIs/SigningLogicInitializable.json +46 -0
  31. package/data-contracts/ABIs/SocialFeatureFactory.json +460 -0
  32. package/data-contracts/ABIs/SocialFeatureStorage.json +225 -0
  33. package/data-contracts/ABIs/SocialFeatureStorageInterface.json +123 -0
  34. package/data-contracts/ABIs/TestContract.json +135 -0
  35. package/data-contracts/ABIs/TestContractInterface.json +19 -0
  36. package/data-contracts/ABIs/TestContractWithStorage.json +165 -0
  37. package/data-contracts/ABIs/TestContractWithStorageInterface.json +24 -0
  38. package/data-contracts/ABIs/TestStorage.json +144 -0
  39. package/data-contracts/ABIs/TestStorageInterface.json +42 -0
  40. package/data-contracts/ABIs/TestUserReplicaSetManager.json +432 -0
  41. package/data-contracts/ABIs/TrackFactory.json +391 -0
  42. package/data-contracts/ABIs/TrackFactoryInterface.json +73 -0
  43. package/data-contracts/ABIs/TrackStorage.json +223 -0
  44. package/data-contracts/ABIs/TrackStorageInterface.json +121 -0
  45. package/data-contracts/ABIs/UpgradeabilityProxy.json +37 -0
  46. package/data-contracts/ABIs/UserFactory.json +657 -0
  47. package/data-contracts/ABIs/UserFactoryInterface.json +65 -0
  48. package/data-contracts/ABIs/UserLibraryFactory.json +334 -0
  49. package/data-contracts/ABIs/UserReplicaSetManager.json +418 -0
  50. package/data-contracts/ABIs/UserStorage.json +233 -0
  51. package/data-contracts/ABIs/UserStorageInterface.json +93 -0
  52. package/data-contracts/signatureSchemas.ts +1236 -0
  53. package/dist/core.d.ts +446 -0
  54. package/dist/core.js +769 -0
  55. package/dist/core.js.map +1 -0
  56. package/dist/index.d.ts +689 -0
  57. package/dist/index.js +72850 -0
  58. package/dist/index.js.map +1 -0
  59. package/eth-contracts/ABIs/Address.json +4 -0
  60. package/eth-contracts/ABIs/AudiusAdminUpgradeabilityProxy.json +105 -0
  61. package/eth-contracts/ABIs/AudiusClaimDistributor.json +4968 -0
  62. package/eth-contracts/ABIs/AudiusToken.json +724 -0
  63. package/eth-contracts/ABIs/BaseUpgradeabilityProxy.json +23 -0
  64. package/eth-contracts/ABIs/Checkpointing.json +4 -0
  65. package/eth-contracts/ABIs/ClaimsManager.json +539 -0
  66. package/eth-contracts/ABIs/Context.json +11 -0
  67. package/eth-contracts/ABIs/DelegateManager.json +989 -0
  68. package/eth-contracts/ABIs/DelegateManagerV2.json +1049 -0
  69. package/eth-contracts/ABIs/DelegateManagerV2Bad.json +1049 -0
  70. package/eth-contracts/ABIs/ERC20.json +252 -0
  71. package/eth-contracts/ABIs/ERC20Burnable.json +287 -0
  72. package/eth-contracts/ABIs/ERC20Detailed.json +270 -0
  73. package/eth-contracts/ABIs/ERC20Mintable.json +364 -0
  74. package/eth-contracts/ABIs/ERC20Pausable.json +397 -0
  75. package/eth-contracts/ABIs/EthRewardsManager.json +174 -0
  76. package/eth-contracts/ABIs/Governance.json +938 -0
  77. package/eth-contracts/ABIs/GovernanceUpgraded.json +953 -0
  78. package/eth-contracts/ABIs/GovernanceV2.json +938 -0
  79. package/eth-contracts/ABIs/IERC20.json +200 -0
  80. package/eth-contracts/ABIs/Initializable.json +4 -0
  81. package/eth-contracts/ABIs/InitializableV2.json +14 -0
  82. package/eth-contracts/ABIs/Migrations.json +71 -0
  83. package/eth-contracts/ABIs/MinterRole.json +91 -0
  84. package/eth-contracts/ABIs/MockAccount.json +62 -0
  85. package/eth-contracts/ABIs/MockDelegateManager.json +55 -0
  86. package/eth-contracts/ABIs/MockStakingCaller.json +259 -0
  87. package/eth-contracts/ABIs/MockWormhole.json +106 -0
  88. package/eth-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  89. package/eth-contracts/ABIs/Ownable.json +93 -0
  90. package/eth-contracts/ABIs/Pausable.json +150 -0
  91. package/eth-contracts/ABIs/PauserRole.json +91 -0
  92. package/eth-contracts/ABIs/Proxy.json +10 -0
  93. package/eth-contracts/ABIs/Registry.json +288 -0
  94. package/eth-contracts/ABIs/Roles.json +4 -0
  95. package/eth-contracts/ABIs/SafeERC20.json +4 -0
  96. package/eth-contracts/ABIs/SafeMath.json +4 -0
  97. package/eth-contracts/ABIs/ServiceProviderFactory.json +1153 -0
  98. package/eth-contracts/ABIs/ServiceTypeManager.json +337 -0
  99. package/eth-contracts/ABIs/Staking.json +555 -0
  100. package/eth-contracts/ABIs/StakingUpgraded.json +570 -0
  101. package/eth-contracts/ABIs/TestContract.json +44 -0
  102. package/eth-contracts/ABIs/TrustedNotifierManager.json +265 -0
  103. package/eth-contracts/ABIs/Uint256Helpers.json +4 -0
  104. package/eth-contracts/ABIs/UpgradeabilityProxy.json +40 -0
  105. package/eth-contracts/ABIs/Wormhole.json +45 -0
  106. package/eth-contracts/ABIs/WormholeClient.json +155 -0
  107. package/examples/file.mp3 +0 -0
  108. package/examples/initAudiusLibs.js +86 -0
  109. package/examples/initializeVersions.js +95 -0
  110. package/examples/pic.jpg +0 -0
  111. package/initScripts/configureLocalDiscProv.js +167 -0
  112. package/initScripts/helpers/claim.js +43 -0
  113. package/initScripts/helpers/distributeTokens.js +24 -0
  114. package/initScripts/helpers/spRegistration.js +138 -0
  115. package/initScripts/helpers/utils.js +34 -0
  116. package/initScripts/helpers/version.js +93 -0
  117. package/initScripts/local.js +617 -0
  118. package/initScripts/mainnet.js +131 -0
  119. package/initScripts/manageProdRelayerWallets.js +191 -0
  120. package/package.json +125 -0
  121. package/rollup.config.js +164 -0
  122. package/scripts/AudiusClaimDistributor.json +4968 -0
  123. package/scripts/Wormhole.json +155 -0
  124. package/scripts/addCIDToIpldBlacklist.js +124 -0
  125. package/scripts/circleci-test.sh +53 -0
  126. package/scripts/communityRewards/transferCommunityRewardsToSolana.js +222 -0
  127. package/scripts/ipfs.sh +58 -0
  128. package/scripts/migrate_contracts.sh +25 -0
  129. package/scripts/reset.sh +65 -0
  130. package/scripts/test.sh +77 -0
  131. package/src/api/account.js +670 -0
  132. package/src/api/base.js +122 -0
  133. package/src/api/file.js +168 -0
  134. package/src/api/playlist.js +328 -0
  135. package/src/api/rewards.d.ts +4 -0
  136. package/src/api/rewards.js +682 -0
  137. package/src/api/serviceProvider.js +154 -0
  138. package/src/api/track.js +604 -0
  139. package/src/api/user.js +888 -0
  140. package/src/api/user.test.js +172 -0
  141. package/src/constants.ts +7 -0
  142. package/src/core.ts +3 -0
  143. package/src/index.js +6 -0
  144. package/src/libs.d.ts +3 -0
  145. package/src/libs.js +619 -0
  146. package/src/sanityChecks/addSecondaries.js +40 -0
  147. package/src/sanityChecks/assignReplicaSetIfNecessary.js +10 -0
  148. package/src/sanityChecks/index.d.ts +9 -0
  149. package/src/sanityChecks/index.js +31 -0
  150. package/src/sanityChecks/isCreator.js +73 -0
  151. package/src/sanityChecks/needsRecoveryEmail.js +20 -0
  152. package/src/sanityChecks/rolloverNodes.js +74 -0
  153. package/src/sanityChecks/sanitizeNodes.js +24 -0
  154. package/src/sanityChecks/syncNodes.js +28 -0
  155. package/src/sdk/constants.ts +10 -0
  156. package/src/sdk/index.ts +1 -0
  157. package/src/sdk/oauth/Oauth.ts +265 -0
  158. package/src/sdk/oauth/index.ts +1 -0
  159. package/src/sdk/sdk.ts +102 -0
  160. package/src/service-selection/ServiceSelection.test.ts +320 -0
  161. package/src/service-selection/ServiceSelection.ts +460 -0
  162. package/src/service-selection/constants.ts +14 -0
  163. package/src/service-selection/index.ts +1 -0
  164. package/src/services/ABIDecoder/AudiusABIDecoder.ts +71 -0
  165. package/src/services/ABIDecoder/index.ts +1 -0
  166. package/src/services/comstock/Comstock.ts +39 -0
  167. package/src/services/comstock/index.ts +1 -0
  168. package/src/services/contracts/ContractClient.ts +227 -0
  169. package/src/services/contracts/GovernedContractClient.ts +53 -0
  170. package/src/services/contracts/ProviderSelection.ts +42 -0
  171. package/src/services/creatorNode/CreatorNode.ts +1065 -0
  172. package/src/services/creatorNode/CreatorNodeSelection.test.ts +997 -0
  173. package/src/services/creatorNode/CreatorNodeSelection.ts +488 -0
  174. package/src/services/creatorNode/constants.ts +10 -0
  175. package/src/services/creatorNode/index.ts +2 -0
  176. package/src/services/dataContracts/AudiusContracts.ts +234 -0
  177. package/src/services/dataContracts/IPLDBlacklistFactoryClient.ts +73 -0
  178. package/src/services/dataContracts/PlaylistFactoryClient.ts +370 -0
  179. package/src/services/dataContracts/RegistryClient.ts +95 -0
  180. package/src/services/dataContracts/SocialFeatureFactoryClient.ts +196 -0
  181. package/src/services/dataContracts/TrackFactoryClient.ts +131 -0
  182. package/src/services/dataContracts/UserFactoryClient.ts +351 -0
  183. package/src/services/dataContracts/UserLibraryFactoryClient.ts +115 -0
  184. package/src/services/dataContracts/UserReplicaSetManagerClient.ts +206 -0
  185. package/src/services/dataContracts/index.ts +1 -0
  186. package/src/services/discoveryProvider/DiscoveryProvider.ts +1168 -0
  187. package/src/services/discoveryProvider/DiscoveryProviderSelection.test.ts +536 -0
  188. package/src/services/discoveryProvider/DiscoveryProviderSelection.ts +383 -0
  189. package/src/services/discoveryProvider/constants.ts +13 -0
  190. package/src/services/discoveryProvider/index.ts +1 -0
  191. package/src/services/discoveryProvider/requests.ts +629 -0
  192. package/src/services/ethContracts/AudiusTokenClient.ts +163 -0
  193. package/src/services/ethContracts/ClaimDistributionClient.ts +45 -0
  194. package/src/services/ethContracts/ClaimsManagerClient.ts +102 -0
  195. package/src/services/ethContracts/DelegateManagerClient.ts +480 -0
  196. package/src/services/ethContracts/EthContracts.ts +359 -0
  197. package/src/services/ethContracts/EthRewardsManagerClient.ts +33 -0
  198. package/src/services/ethContracts/GovernanceClient.ts +451 -0
  199. package/src/services/ethContracts/RegistryClient.ts +33 -0
  200. package/src/services/ethContracts/ServiceProviderFactoryClient.ts +691 -0
  201. package/src/services/ethContracts/ServiceTypeManagerClient.ts +112 -0
  202. package/src/services/ethContracts/StakingProxyClient.ts +97 -0
  203. package/src/services/ethContracts/TrustedNotifierManagerClient.ts +101 -0
  204. package/src/services/ethContracts/WormholeClient.ts +97 -0
  205. package/src/services/ethContracts/index.ts +1 -0
  206. package/src/services/ethWeb3Manager/EthWeb3Manager.ts +239 -0
  207. package/src/services/ethWeb3Manager/index.ts +1 -0
  208. package/src/services/hedgehog/Hedgehog.ts +96 -0
  209. package/src/services/hedgehog/index.ts +1 -0
  210. package/src/services/identity/IdentityService.ts +551 -0
  211. package/src/services/identity/index.ts +1 -0
  212. package/src/services/identity/requests.ts +65 -0
  213. package/src/services/schemaValidator/SchemaValidator.ts +105 -0
  214. package/src/services/schemaValidator/index.ts +1 -0
  215. package/src/services/schemaValidator/schemas/trackSchema.json +267 -0
  216. package/src/services/schemaValidator/schemas/userSchema.json +230 -0
  217. package/src/services/solanaAudiusData/errors.ts +20 -0
  218. package/src/services/solanaAudiusData/index.ts +1189 -0
  219. package/src/services/solanaWeb3Manager/errors.js +101 -0
  220. package/src/services/solanaWeb3Manager/index.d.ts +46 -0
  221. package/src/services/solanaWeb3Manager/index.js +655 -0
  222. package/src/services/solanaWeb3Manager/padBNToUint8Array.ts +7 -0
  223. package/src/services/solanaWeb3Manager/rewards.js +941 -0
  224. package/src/services/solanaWeb3Manager/rewardsAttester.ts +1093 -0
  225. package/src/services/solanaWeb3Manager/tokenAccount.js +149 -0
  226. package/src/services/solanaWeb3Manager/transactionHandler.js +345 -0
  227. package/src/services/solanaWeb3Manager/transfer.js +272 -0
  228. package/src/services/solanaWeb3Manager/userBank.js +160 -0
  229. package/src/services/solanaWeb3Manager/utils.d.ts +31 -0
  230. package/src/services/solanaWeb3Manager/utils.js +163 -0
  231. package/src/services/solanaWeb3Manager/wAudio.js +28 -0
  232. package/src/services/solanaWeb3Manager/wAudio.test.js +30 -0
  233. package/src/services/web3Manager/Web3Config.ts +14 -0
  234. package/src/services/web3Manager/Web3Manager.ts +360 -0
  235. package/src/services/web3Manager/XMLHttpRequest.ts +11 -0
  236. package/src/services/web3Manager/index.ts +2 -0
  237. package/src/services/wormhole/index.js +424 -0
  238. package/src/types.ts +8 -0
  239. package/src/userStateManager.ts +53 -0
  240. package/src/utils/apiSigning.ts +51 -0
  241. package/src/utils/captcha.ts +97 -0
  242. package/src/utils/estimateGas.ts +64 -0
  243. package/src/utils/fileHasher.ts +278 -0
  244. package/src/utils/importContractABI.d.ts +9 -0
  245. package/src/utils/importContractABI.js +19 -0
  246. package/src/utils/index.ts +11 -0
  247. package/src/utils/multiProvider.ts +72 -0
  248. package/src/utils/network.test.ts +127 -0
  249. package/src/utils/network.ts +308 -0
  250. package/src/utils/promiseFight.test.ts +87 -0
  251. package/src/utils/promiseFight.ts +36 -0
  252. package/src/utils/signatures.ts +139 -0
  253. package/src/utils/types.ts +34 -0
  254. package/src/utils/utils.test.ts +36 -0
  255. package/src/utils/utils.ts +235 -0
  256. package/src/utils/uuid.ts +14 -0
  257. package/src/web3.d.ts +9 -0
  258. package/src/web3.js +8 -0
  259. package/tests/assets/static_image.png +0 -0
  260. package/tests/assets/static_text.txt +1 -0
  261. package/tests/audiusTokenClientTest.js +37 -0
  262. package/tests/creatorNodeTest.js +19 -0
  263. package/tests/fileHasherTest.js +125 -0
  264. package/tests/governanceTest.js +382 -0
  265. package/tests/helpers.js +105 -0
  266. package/tests/index.js +14 -0
  267. package/tests/playlistClientTest.js +157 -0
  268. package/tests/providerSelectionTest.js +241 -0
  269. package/tests/registryClientTest.js +19 -0
  270. package/tests/rewardsAttesterTest.js +373 -0
  271. package/tests/serviceTypeManagerClientTest.js +33 -0
  272. package/tests/socialFeatureClientTest.js +79 -0
  273. package/tests/stakingTest.js +302 -0
  274. package/tests/trackClientTest.js +86 -0
  275. package/tests/userClientTest.js +121 -0
  276. package/tsconfig.json +10 -0
  277. package/types/@audius-hedgehog/index.d.ts +39 -0
  278. package/types/abi-decoder/index.d.ts +41 -0
@@ -0,0 +1,383 @@
1
+ import {
2
+ Backup,
3
+ Decision,
4
+ ServiceSelection,
5
+ ServiceSelectionConfig
6
+ } from '../../service-selection'
7
+ import {
8
+ DISCOVERY_PROVIDER_TIMESTAMP,
9
+ DISCOVERY_SERVICE_NAME,
10
+ DEFAULT_UNHEALTHY_BLOCK_DIFF,
11
+ DISCOVERY_PROVIDER_RESELECT_TIMEOUT,
12
+ REGRESSED_MODE_TIMEOUT
13
+ } from './constants'
14
+ import semver from 'semver'
15
+ import type { EthContracts } from '../ethContracts'
16
+ import type { AxiosResponse } from 'axios'
17
+ import type { Maybe, Nullable } from '../../utils'
18
+
19
+ const PREVIOUS_VERSIONS_TO_CHECK = 5
20
+
21
+ let localStorage: Storage
22
+ if (typeof window === 'undefined' || window === null) {
23
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
24
+ const LocalStorage = require('node-localstorage').LocalStorage
25
+ localStorage = new LocalStorage('./local-storage')
26
+ } else {
27
+ localStorage = window.localStorage
28
+ }
29
+
30
+ export type DiscoveryProviderSelectionConfig = Omit<
31
+ ServiceSelectionConfig,
32
+ 'getServices'
33
+ > & {
34
+ reselectTimeout?: number
35
+ selectionCallback?: (endpoint: string, decisionTree: Decision[]) => void
36
+ monitoringCallbacks?: {
37
+ healthCheck: (config: Record<string, unknown>) => void
38
+ request: (config: Record<string, unknown>) => void
39
+ }
40
+ unhealthySlotDiffPlays?: number
41
+ unhealthyBlockDiff?: number
42
+ }
43
+
44
+ export class DiscoveryProviderSelection extends ServiceSelection {
45
+ currentVersion: string
46
+ ethContracts: EthContracts
47
+ reselectTimeout: Maybe<number>
48
+ selectionCallback: Maybe<
49
+ DiscoveryProviderSelectionConfig['selectionCallback']
50
+ >
51
+
52
+ monitoringCallbacks:
53
+ | NonNullable<DiscoveryProviderSelectionConfig['monitoringCallbacks']>
54
+ | {}
55
+
56
+ unhealthySlotDiffPlays: Nullable<number>
57
+ unhealthyBlockDiff: number
58
+ _regressedMode: boolean
59
+ validVersions: Nullable<string[]>
60
+
61
+ constructor(
62
+ config: DiscoveryProviderSelectionConfig,
63
+ ethContracts: EthContracts
64
+ ) {
65
+ super({
66
+ /**
67
+ * Gets the "current" expected service version as well as
68
+ * the list of registered providers from chain
69
+ */
70
+ getServices: async ({ verbose = false } = {}) => {
71
+ this.currentVersion = await ethContracts.getCurrentVersion(
72
+ DISCOVERY_SERVICE_NAME
73
+ )
74
+ const services = await this.ethContracts.getServiceProviderList(
75
+ DISCOVERY_SERVICE_NAME
76
+ )
77
+ return verbose ? services : services.map((e) => e.endpoint)
78
+ },
79
+ ...config
80
+ })
81
+ this.ethContracts = ethContracts
82
+ this.currentVersion = ''
83
+ this.reselectTimeout = config.reselectTimeout
84
+ this.selectionCallback = config.selectionCallback
85
+ this.monitoringCallbacks = config.monitoringCallbacks ?? {}
86
+ this.unhealthySlotDiffPlays = config.unhealthySlotDiffPlays ?? null
87
+ this.unhealthyBlockDiff =
88
+ config.unhealthyBlockDiff ?? DEFAULT_UNHEALTHY_BLOCK_DIFF
89
+
90
+ // Whether or not we are running in `regressed` mode, meaning we were
91
+ // unable to select a discovery provider that was up-to-date. Clients may
92
+ // want to consider blocking writes.
93
+ this._regressedMode = false
94
+
95
+ // List of valid past discovery provider versions registered on chain
96
+ this.validVersions = null
97
+ }
98
+
99
+ /** Retrieves a cached discovery provider from localstorage */
100
+ getCached() {
101
+ if (localStorage) {
102
+ try {
103
+ const discProvTimestamp = localStorage.getItem(
104
+ DISCOVERY_PROVIDER_TIMESTAMP
105
+ )
106
+ if (discProvTimestamp) {
107
+ const { endpoint: latestEndpoint, timestamp } =
108
+ JSON.parse(discProvTimestamp)
109
+
110
+ const inWhitelist =
111
+ !this.whitelist || this.whitelist.has(latestEndpoint)
112
+
113
+ const timeout = this.reselectTimeout
114
+ ? this.reselectTimeout
115
+ : DISCOVERY_PROVIDER_RESELECT_TIMEOUT
116
+ const isExpired = Date.now() - timestamp > timeout
117
+ if (!inWhitelist || isExpired) {
118
+ this.clearCached()
119
+ } else {
120
+ return latestEndpoint
121
+ }
122
+ }
123
+ } catch (e) {
124
+ console.error(
125
+ 'Could not retrieve cached discovery endpoint from localStorage',
126
+ e
127
+ )
128
+ }
129
+ }
130
+ return null
131
+ }
132
+
133
+ /** Clears any cached discovery provider from localstorage */
134
+ clearCached() {
135
+ if (localStorage) {
136
+ localStorage.removeItem(DISCOVERY_PROVIDER_TIMESTAMP)
137
+ }
138
+ }
139
+
140
+ /** Sets a cached discovery provider in localstorage */
141
+ setCached(endpoint: string) {
142
+ localStorage.setItem(
143
+ DISCOVERY_PROVIDER_TIMESTAMP,
144
+ JSON.stringify({ endpoint, timestamp: Date.now() })
145
+ )
146
+ }
147
+
148
+ /** Allows the selection take a shortcut if there's a cached provider */
149
+ override shortcircuit() {
150
+ return this.getCached()
151
+ }
152
+
153
+ override async select() {
154
+ const endpoint = await super.select()
155
+ if (endpoint) {
156
+ this.setCached(endpoint)
157
+ }
158
+ console.info(`Selected discprov ${endpoint}`, this.decisionTree)
159
+ if (this.selectionCallback) {
160
+ this.selectionCallback(endpoint, this.decisionTree)
161
+ }
162
+ return endpoint
163
+ }
164
+
165
+ /**
166
+ * Checks whether a given response is healthy:
167
+ * - Not behind in blocks
168
+ * - 200 response
169
+ * - Current version
170
+ *
171
+ * Other responses are collected in `this.backups` if
172
+ * - Behind by only a patch version
173
+ *
174
+ * @param response axios response
175
+ * @param urlMap health check urls mapped to their cannonical url
176
+ * e.g. https://discoveryprovider.audius.co/health_check => https://discoveryprovider.audius.co
177
+ */
178
+ override isHealthy(response: AxiosResponse, urlMap: Record<string, string>) {
179
+ const { status, data } = response
180
+ const { block_difference: blockDiff, service, version, plays } = data.data
181
+ let slotDiffPlays = null
182
+ if (plays?.tx_info) {
183
+ slotDiffPlays = plays.tx_info.slot_diff
184
+ }
185
+
186
+ if ('healthCheck' in this.monitoringCallbacks) {
187
+ const url = new URL(response.config.url as string)
188
+ try {
189
+ this.monitoringCallbacks.healthCheck({
190
+ endpoint: url.origin,
191
+ pathname: url.pathname,
192
+ queryString: url.search,
193
+ version,
194
+ git: data.data.git,
195
+ blockDifference: blockDiff,
196
+ slotDifferencePlays: slotDiffPlays,
197
+ databaseBlockNumber: data.data.db.number,
198
+ webBlockNumber: data.data.web.blocknumber,
199
+ databaseSize: data.data.database_size,
200
+ databaseConnections: data.data.database_connections,
201
+ totalMemory: data.data.total_memory,
202
+ usedMemory: data.data.used_memory,
203
+ totalStorage: data.data.filesystem_size,
204
+ usedStorage: data.data.filesystem_used,
205
+ receivedBytesPerSec: data.received_bytes_per_sec,
206
+ transferredBytesPerSec: data.transferred_bytes_per_sec,
207
+ challengeLastEventAgeSec: data.challenge_last_event_age_sec
208
+ })
209
+ } catch (e) {
210
+ // Swallow errors -- this method should not throw generally
211
+ console.error(e)
212
+ }
213
+ }
214
+
215
+ if (status !== 200) return false
216
+ if (service !== DISCOVERY_SERVICE_NAME) return false
217
+ if (!semver.valid(version)) return false
218
+
219
+ // If this service is not the same major/minor as what's on chain, reject
220
+ if (
221
+ !this.ethContracts.hasSameMajorAndMinorVersion(
222
+ this.currentVersion,
223
+ version
224
+ )
225
+ ) {
226
+ return false
227
+ }
228
+
229
+ // If this service is behind by patches, add it as a backup and reject
230
+ if (semver.patch(version) < semver.patch(this.currentVersion)) {
231
+ this.addBackup(urlMap[response.config.url as string] as string, data.data)
232
+ return false
233
+ }
234
+
235
+ // If this service is an unhealthy block diff behind, add it as a backup and reject
236
+ if (blockDiff > this.unhealthyBlockDiff) {
237
+ this.addBackup(urlMap[response.config.url as string] as string, data.data)
238
+ return false
239
+ }
240
+
241
+ // If this service is an unhealthy slot diff behind on the plays table, add it
242
+ // as a backup and reject
243
+ if (
244
+ slotDiffPlays !== null &&
245
+ this.unhealthySlotDiffPlays !== null &&
246
+ slotDiffPlays > this.unhealthySlotDiffPlays
247
+ ) {
248
+ this.addBackup(urlMap[response.config.url as string] as string, data.data)
249
+ return false
250
+ }
251
+
252
+ return true
253
+ }
254
+
255
+ /**
256
+ * Estabilishes that connection to discovery providers has regressed
257
+ */
258
+ enterRegressedMode() {
259
+ console.info('Entering regressed mode')
260
+ this._regressedMode = true
261
+ setTimeout(() => {
262
+ console.info('Leaving regressed mode')
263
+ this._regressedMode = false
264
+ }, REGRESSED_MODE_TIMEOUT)
265
+ }
266
+
267
+ setUnhealthyBlockDiff(updatedDiff = DEFAULT_UNHEALTHY_BLOCK_DIFF) {
268
+ this.unhealthyBlockDiff = updatedDiff
269
+ }
270
+
271
+ setUnhealthySlotDiffPlays(updatedDiff: number) {
272
+ this.unhealthySlotDiffPlays = updatedDiff
273
+ }
274
+
275
+ isInRegressedMode() {
276
+ return this._regressedMode
277
+ }
278
+
279
+ /**
280
+ * In the case of no "healthy" services, we resort to backups in the following order:
281
+ * 1. Pick the most recent (patch) version that's not behind
282
+ * 2. Pick the least behind provider that is a valid patch version and enter "regressed mode"
283
+ * 3. Pick `null`
284
+ */
285
+ override async selectFromBackups() {
286
+ const versions: string[] = []
287
+ const blockDiffs: number[] = []
288
+
289
+ const versionMap: Record<string, string[]> = {}
290
+ const blockDiffMap: Record<string, string[]> = {}
291
+
292
+ // Go backwards in time on chain and get the registered versions up to PREVIOUS_VERSIONS_TO_CHECK.
293
+ // Record those versions in a set and validate any backups against that set.
294
+ // TODO: Clean up this logic when we can validate a specific version rather
295
+ // than traversing backwards through all the versions
296
+ if (!this.validVersions) {
297
+ this.validVersions = [this.currentVersion]
298
+ const numberOfVersions = await this.ethContracts.getNumberOfVersions(
299
+ DISCOVERY_SERVICE_NAME
300
+ )
301
+ for (
302
+ let i = 0;
303
+ i < Math.min(PREVIOUS_VERSIONS_TO_CHECK, numberOfVersions - 1);
304
+ ++i
305
+ ) {
306
+ const pastServiceVersion = await this.ethContracts.getVersion(
307
+ DISCOVERY_SERVICE_NAME,
308
+ // Exclude the latest version when querying older versions
309
+ // Latest index is numberOfVersions - 1, so 2nd oldest version starts at numberOfVersions - 2
310
+ numberOfVersions - 2 - i
311
+ )
312
+ this.validVersions.push(pastServiceVersion)
313
+ }
314
+ }
315
+
316
+ // Go through each backup and create two keyed maps:
317
+ // { semver => [provider] }
318
+ // { blockdiff => [provider] }
319
+ Object.keys(this.backups).forEach((backup) => {
320
+ const { block_difference: blockDiff, version } = this.backups[
321
+ backup
322
+ ] as Backup
323
+
324
+ let isVersionOk = false
325
+ for (let i = 0; i < (this.validVersions as string[]).length; ++i) {
326
+ if (
327
+ this.ethContracts.hasSameMajorAndMinorVersion(
328
+ this.validVersions?.[i] as string,
329
+ version
330
+ )
331
+ ) {
332
+ isVersionOk = true
333
+ break
334
+ }
335
+ }
336
+ // Filter out any version that wasn't valid given what's registered on chain
337
+ if (!isVersionOk) return
338
+
339
+ versions.push(version)
340
+ blockDiffs.push(blockDiff)
341
+
342
+ if (version in versionMap) {
343
+ versionMap[version]?.push(backup)
344
+ } else {
345
+ versionMap[version] = [backup]
346
+ }
347
+
348
+ if (blockDiff in blockDiffMap) {
349
+ blockDiffMap[blockDiff]?.push(backup)
350
+ } else {
351
+ blockDiffMap[blockDiff] = [backup]
352
+ }
353
+ })
354
+
355
+ // Sort the versions by desc semver
356
+ const sortedVersions = versions.sort(semver.rcompare)
357
+
358
+ // Select the closest version that's a healthy # of blocks behind
359
+ let selected: string = ''
360
+ for (const version of sortedVersions) {
361
+ const endpoints = versionMap[version] as string[]
362
+ for (let i = 0; i < endpoints.length; ++i) {
363
+ if (
364
+ (this.backups[endpoints[i] as string]?.block_difference as number) <
365
+ this.unhealthyBlockDiff
366
+ ) {
367
+ selected = endpoints[i] as string
368
+ break
369
+ }
370
+ }
371
+ if (selected) return selected
372
+ }
373
+
374
+ // Select the best block diff provider
375
+ // eslint-disable-next-line @typescript-eslint/require-array-sort-compare
376
+ const bestBlockDiff = blockDiffs.sort()[0] as number
377
+
378
+ selected = blockDiffMap[bestBlockDiff]?.[0] as string
379
+ this.enterRegressedMode()
380
+
381
+ return selected
382
+ }
383
+ }
@@ -0,0 +1,13 @@
1
+ export const DISCOVERY_PROVIDER_TIMESTAMP =
2
+ '@audius/libs:discovery-node-timestamp'
3
+ export const DISCOVERY_SERVICE_NAME = 'discovery-node'
4
+ export const DEFAULT_UNHEALTHY_BLOCK_DIFF = 15
5
+ export const REGRESSED_MODE_TIMEOUT = 2 * 60 * 1000 // two minutes
6
+
7
+ // When to time out the cached discovery provider
8
+ export const DISCOVERY_PROVIDER_RESELECT_TIMEOUT =
9
+ 10 /* min */ * 60 /* seconds */ * 1000 /* millisec */
10
+ // How often to make sure the cached discovery provider is fresh
11
+ export const DISCOVERY_PROVIDER_TIMESTAMP_INTERVAL = 5000
12
+
13
+ export const REQUEST_TIMEOUT_MS = 30 /* seconds */ * 1000 /* millisec */
@@ -0,0 +1 @@
1
+ export * from './DiscoveryProvider'