Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/config/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ const SERVER_CONFIG: StrictServerConfiguration = {
avoidOurIndexInFactTell: false, //initial testing shows this may cause issues so leaving it off for now
checkDestLimits: true,
checkDestLimitCount: 5,
bypassAccountCache: false,
},
sharding: { nodesPerConsensusGroup: 5, nodesPerEdge: 2, executeInOneShard: false },
mode: ServerMode.Release,
Expand Down
2 changes: 2 additions & 0 deletions src/shardus/shardus-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,8 @@ export interface ServerConfiguration {
checkDestLimits: boolean
// how many times can this destination address show up in the queue before we avoid sending to it
checkDestLimitCount: number
// bypass account cache and load account data directly from storage
bypassAccountCache: boolean
}
/** Options for sharding calculations */
sharding?: {
Expand Down
20 changes: 18 additions & 2 deletions src/state-manager/AccountCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,28 @@ class AccountCache {
// at the end of buildPartitionHashesForNode gets set to the working/current cycle.
// if TXs come in that are newer they get put in the future list and are not part of the parition hash report yet

hasAccount(accountId: string): boolean {
async hasAccount(accountId: string): Promise<boolean> {
if (this.config.stateManager.bypassAccountCache) {
const accountDataList = await this.app.getAccountDataByList([accountId])
return !!(accountDataList && accountDataList.length > 0 && accountDataList[0] != null)
}
return this.accountsHashCache3.accountHashMap.has(accountId)
}

//just gets the newest seen hash. does that cause issues?
getAccountHash(accountId: string): AccountHashCache {
async getAccountHash(accountId: string): Promise<AccountHashCache> {
if (this.config.stateManager.bypassAccountCache) {
const accountDataList = await this.app.getAccountDataByList([accountId])
if (accountDataList && accountDataList.length > 0 && accountDataList[0] != null) {
const accountData = accountDataList[0]
return {
h: accountData.stateId,
t: accountData.timestamp || Date.now(),
c: this.stateManager?.currentCycleShardData?.cycleNumber || 0
}
}
return null
}
if (this.accountsHashCache3.accountHashMap.has(accountId) === false) {
return null
}
Expand Down
6 changes: 3 additions & 3 deletions src/state-manager/AccountGlobals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,13 @@ class AccountGlobals {
/* prettier-ignore */ nestedCountersInstance.countEvent('sync', `DATASYNC: getGlobalListEarly success:${this.hasknownGlobals}`)
}

getGlobalDebugReport(): {
async getGlobalDebugReport(): Promise<{
globalAccountSummary: { id: string; state: string; ts: number }[]
globalStateHash: string
} {
}> {
const globalAccountSummary = []
for (const globalID in this.globalAccountSet.keys()) {
const accountHash = this.stateManager.accountCache.getAccountHash(globalID)
const accountHash = await this.stateManager.accountCache.getAccountHash(globalID)
const summaryObj = { id: globalID, state: accountHash.h, ts: accountHash.t }
globalAccountSummary.push(summaryObj)
}
Expand Down
47 changes: 19 additions & 28 deletions src/state-manager/AccountPatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ class AccountPatcher {
continue
}
// check if we have already repaired this account
const accountHashCache = this.stateManager.accountCache.getAccountHash(accountID)
const accountHashCache = await this.stateManager.accountCache.getAccountHash(accountID)
if (accountHashCache != null && accountHashCache.h === hash) {
nestedCountersInstance.countEvent(
'accountPatcher',
Expand Down Expand Up @@ -1607,7 +1607,7 @@ class AccountPatcher {
}

const trieAccount = this.getAccountTreeInfo(id)
const accountHash = this.stateManager.accountCache.getAccountHash(id)
const accountHash = await this.stateManager.accountCache.getAccountHash(id)
const accountHashFull = this.stateManager.accountCache.getAccountDebugObject(id) //this.stateManager.accountCache.accountsHashCache3.accountHashMap.get(id)
const accountData = await this.app.getAccountDataByList([id])
res.write(`trieAccount: ${Utils.safeStringify(trieAccount)} \n`)
Expand Down Expand Up @@ -2353,8 +2353,7 @@ class AccountPatcher {
if (coverageEntry == null || coverageEntry.firstChoice == null) {
const numActiveNodes = this.stateManager.currentCycleShardData.nodes.length
this.statemanager_fatal(
`getNodeForQuery null ${coverageEntry == null} ${
coverageEntry?.firstChoice == null
`getNodeForQuery null ${coverageEntry == null} ${coverageEntry?.firstChoice == null
} numActiveNodes:${numActiveNodes}`,
`getNodeForQuery null ${coverageEntry == null} ${coverageEntry?.firstChoice == null}`
)
Expand Down Expand Up @@ -2772,7 +2771,7 @@ class AccountPatcher {

// for non-wrapped ranges
if (startRadix <= endRadix) {
for (let i = 0; i <= isInsyncResult.radixes.length; i++) {
for (let i = 0; i < isInsyncResult.radixes.length; i++) {
const radixEntry = isInsyncResult.radixes[i]
if (radixEntry.radix >= startRadix && radixEntry.radix <= endRadix) {
radixEntry.recentRuntimeSync = true
Expand All @@ -2781,7 +2780,7 @@ class AccountPatcher {
}
// for wrapped ranges because we start at the end and wrap around to the beginning of 32 byte address space
} else {
for (let i = 0; i <= isInsyncResult.radixes.length; i++) {
for (let i = 0; i < isInsyncResult.radixes.length; i++) {
const radixEntry = isInsyncResult.radixes[i]
if (radixEntry.radix >= startRadix || radixEntry.radix <= endRadix) {
radixEntry.recentRuntimeSync = true
Expand Down Expand Up @@ -2872,8 +2871,7 @@ class AccountPatcher {
/* prettier-ignore */ nestedCountersInstance.countEvent(`accountPatcher`, `not enough votes ${radix} ${utils.makeShortHash(votesMap.bestHash)} uniqueVotes: ${votesMap.allVotes.size}`, 1)
this.statemanager_fatal(
'debug findBadAccounts',
`debug findBadAccounts ${cycle}: ${radix} bestVotes${
votesMap.bestVotes
`debug findBadAccounts ${cycle}: ${radix} bestVotes${votesMap.bestVotes
} < minVotes:${minVotes} uniqueVotes: ${votesMap.allVotes.size} ${utils.stringifyReduce(simpleMap)}`
)
}
Expand Down Expand Up @@ -2941,10 +2939,8 @@ class AccountPatcher {
}
this.statemanager_fatal(
'debug findBadAccounts',
`debug findBadAccounts ${cycle}: ${
radixToFix.radix
} isInNonConsensusRange: ${hasNonConsensusRange} isInNonStorageRange: ${hasNonStorageRange} bestVotes ${
votesMap.bestVotes
`debug findBadAccounts ${cycle}: ${radixToFix.radix
} isInNonConsensusRange: ${hasNonConsensusRange} isInNonStorageRange: ${hasNonStorageRange} bestVotes ${votesMap.bestVotes
} minVotes:${minVotes} uniqueVotes: ${votesMap.allVotes.size} ${utils.stringifyReduce(simpleMap)}`
)
}
Expand Down Expand Up @@ -3123,7 +3119,7 @@ class AccountPatcher {
// (we are not supposed to test syncing ranges , but maybe that is out of phase?)

//only do this check if the account is new. It was skipping potential oos situations.
const accountMemData: AccountHashCache = this.stateManager.accountCache.getAccountHash(
const accountMemData: AccountHashCache = await this.stateManager.accountCache.getAccountHash(
potentalGoodAcc.accountID
)
if (accountMemData != null && accountMemData.h === potentalGoodAcc.hash) {
Expand Down Expand Up @@ -3698,8 +3694,7 @@ class AccountPatcher {

if (logFlags.debug) {
this.mainLogger.debug(
`badAccounts cycle: ${cycle}, ourBadAccounts: ${
results.badAccounts.length
`badAccounts cycle: ${cycle}, ourBadAccounts: ${results.badAccounts.length
}, ourBadAccounts: ${Utils.safeStringify(results.badAccounts)}`
)
}
Expand All @@ -3709,8 +3704,7 @@ class AccountPatcher {
accountsTheyNeedToRepair = accountsTheyNeedToRepair.concat(results.extraBadAccounts)
}
this.mainLogger.debug(
`badAccounts cycle: ${cycle}, accountsTheyNeedToRepair: ${
accountsTheyNeedToRepair.length
`badAccounts cycle: ${cycle}, accountsTheyNeedToRepair: ${accountsTheyNeedToRepair.length
}, accountsTheyNeedToRepair: ${Utils.safeStringify(accountsTheyNeedToRepair)}`
)
this.requestOtherNodesToRepair(accountsTheyNeedToRepair)
Expand Down Expand Up @@ -3771,8 +3765,8 @@ class AccountPatcher {
for (let i = 0; i < wrappedDataList.length; i++) {
let wrappedData: Shardus.WrappedData = wrappedDataList[i]
let nodeWeAsked = repairDataResponse.nodes[i]
if (this.stateManager.accountCache.hasAccount(wrappedData.accountId)) {
const accountMemData: AccountHashCache = this.stateManager.accountCache.getAccountHash(wrappedData.accountId)
if (await this.stateManager.accountCache.hasAccount(wrappedData.accountId)) {
const accountMemData: AccountHashCache = await this.stateManager.accountCache.getAccountHash(wrappedData.accountId)
// dont allow an older timestamp to overwrite a newer copy of data we have.
// we may need to do more work to make sure this can not cause an un repairable situation
if (wrappedData.timestamp < accountMemData.t) {
Expand All @@ -3782,8 +3776,7 @@ class AccountPatcher {
'checkAndSetAccountData updateTooOld',
`checkAndSetAccountData updateTooOld ${cycle}: acc:${utils.stringifyReduce(
wrappedData.accountId
)} updateTS:${wrappedData.timestamp} updateHash:${utils.stringifyReduce(wrappedData.stateId)} cacheTS:${
accountMemData.t
)} updateTS:${wrappedData.timestamp} updateHash:${utils.stringifyReduce(wrappedData.stateId)} cacheTS:${accountMemData.t
} cacheHash:${utils.stringifyReduce(accountMemData.h)}`
)
filterStats.tooOld++
Expand Down Expand Up @@ -3982,7 +3975,7 @@ class AccountPatcher {
)
}
const appliedFixes = Math.max(0, wrappedDataListFiltered.length - failedHashes.length)
/* prettier-ignore */ nestedCountersInstance.countEvent('accountPatcher', 'writeCombinedAccountDataToBackups', Math.max(0,wrappedDataListFiltered.length - failedHashes.length))
/* prettier-ignore */ nestedCountersInstance.countEvent('accountPatcher', 'writeCombinedAccountDataToBackups', Math.max(0, wrappedDataListFiltered.length - failedHashes.length))
/* prettier-ignore */ nestedCountersInstance.countEvent('accountPatcher', `p.repair applied c:${cycle} bad:${results.badAccounts.length} received:${wrappedDataList.length} failedH: ${failedHashes.length} filtered:${utils.stringifyReduce(filterStats)} stats:${utils.stringifyReduce(results.stats)} getAccountStats: ${utils.stringifyReduce(getAccountStats)} extraBadKeys:${results.extraBadKeys.length}`, appliedFixes)

this.stateManager.cycleDebugNotes.patchedAccounts = appliedFixes //per cycle debug info
Expand All @@ -4000,8 +3993,7 @@ class AccountPatcher {
)
this.statemanager_fatal(
'isInSync = false',
`bad accounts cycle:${cycle} bad:${results.badAccounts.length} received:${wrappedDataList.length} failedH: ${
failedHashes.length
`bad accounts cycle:${cycle} bad:${results.badAccounts.length} received:${wrappedDataList.length} failedH: ${failedHashes.length
} filtered:${utils.stringifyReduce(filterStats)} stats:${utils.stringifyReduce(
results.stats
)} getAccountStats: ${utils.stringifyReduce(getAccountStats)} details: ${utils.stringifyReduceLimit(
Expand Down Expand Up @@ -4048,7 +4040,7 @@ class AccountPatcher {
}
if (combinedAccountStateData.length > 0) {
await this.stateManager.storage.addAccountStates(combinedAccountStateData)
/* prettier-ignore */ nestedCountersInstance.countEvent('accountPatcher', `p.repair stateTable c:${cycle} acc:#${updatedAccounts.length} st#:${combinedAccountStateData.length} missed#${combinedAccountStateData.length-updatedAccounts.length}`, combinedAccountStateData.length)
/* prettier-ignore */ nestedCountersInstance.countEvent('accountPatcher', `p.repair stateTable c:${cycle} acc:#${updatedAccounts.length} st#:${combinedAccountStateData.length} missed#${combinedAccountStateData.length - updatedAccounts.length}`, combinedAccountStateData.length)
}

if (wrappedDataListFiltered.length > 0) {
Expand Down Expand Up @@ -4083,7 +4075,7 @@ class AccountPatcher {
failHistoryObject.e = this.failEndCycle
failHistoryObject.cycles = this.failEndCycle - this.failStartCycle

/* prettier-ignore */ nestedCountersInstance.countEvent(`accountPatcher`, `inSync again. ${Utils.safeStringify(this.syncFailHistory[this.syncFailHistory.length -1])}`)
/* prettier-ignore */ nestedCountersInstance.countEvent(`accountPatcher`, `inSync again. ${Utils.safeStringify(this.syncFailHistory[this.syncFailHistory.length - 1])}`)

//this is not really a fatal log so should be removed eventually. is is somewhat usefull context though when debugging.
this.statemanager_fatal(`inSync again`, Utils.safeStringify(this.syncFailHistory))
Expand Down Expand Up @@ -4587,8 +4579,7 @@ class AccountPatcher {
}

stream.write(
`node: ${nodesCovered.id} ${nodesCovered.ipPort}\tgraph: ${partitionGraph}\thome: ${
nodesCovered.hP
`node: ${nodesCovered.id} ${nodesCovered.ipPort}\tgraph: ${partitionGraph}\thome: ${nodesCovered.hP
} data:${Utils.safeStringify(nodesCovered)}\n`
)
}
Expand Down
16 changes: 8 additions & 8 deletions src/state-manager/PartitionStats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ class PartitionStats {
}

//todo , I think this is redundant and removable now.
hasAccountBeenSeenByStats(accountId: string): boolean {
return this.accountCache.hasAccount(accountId)
async hasAccountBeenSeenByStats(accountId: string): Promise<boolean> {
return await this.accountCache.hasAccount(accountId)
}

/**
Expand Down Expand Up @@ -424,7 +424,7 @@ class PartitionStats {
* @param accountDataRaw
* @param debugMsg
*/
statsDataSummaryInit(cycle: number, accountId: string, accountDataRaw: unknown, debugMsg: string): void {
async statsDataSummaryInit(cycle: number, accountId: string, accountDataRaw: unknown, debugMsg: string): Promise<void> {
const opCounter = this.statsProcessCounter++
if (this.invasiveDebugInfo)
this.mainLogger.debug(
Expand All @@ -436,7 +436,7 @@ class PartitionStats {
const blob: StateManagerTypes.StateManagerTypes.SummaryBlob = this.getSummaryBlob(accountId)
blob.counter++

if (this.accountCache.hasAccount(accountId)) {
if (await this.accountCache.hasAccount(accountId)) {
return
}
const accountInfo = this.app.getTimestampAndHashFromAccount(accountDataRaw)
Expand Down Expand Up @@ -513,12 +513,12 @@ class PartitionStats {
* @param accountDataAfter
* @param debugMsg
*/
statsDataSummaryUpdate(
async statsDataSummaryUpdate(
cycle: number,
accountDataBefore: unknown,
accountDataAfter: Shardus.WrappedData,
debugMsg: string
): void {
): Promise<void> {
const opCounter = this.statsProcessCounter++
if (this.invasiveDebugInfo)
this.mainLogger.debug(
Expand Down Expand Up @@ -547,8 +547,8 @@ class PartitionStats {
const timestamp = accountDataAfter.timestamp // this.app.getAccountTimestamp(accountId)
const hash = accountDataAfter.stateId //this.app.getStateId(accountId)

if (this.accountCache.hasAccount(accountId)) {
const accountMemData: AccountHashCache = this.accountCache.getAccountHash(accountId)
if (await this.accountCache.hasAccount(accountId)) {
const accountMemData: AccountHashCache = await this.accountCache.getAccountHash(accountId)
if (accountMemData.t > timestamp) {
/* prettier-ignore */ if (logFlags.error) this.mainLogger.error(`statsDataSummaryUpdate: good error?: 2: dont update stats with older data skipping update ${utils.makeShortHash(accountId)} ${debugMsg} ${accountMemData.t} > ${timestamp} afterHash:${utils.makeShortHash(accountDataAfter.stateId)}`)
return
Expand Down
18 changes: 12 additions & 6 deletions src/state-manager/TransactionQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,12 @@ class TransactionQueue {
* @param queueEntry
*/
async commitConsensedTransaction(queueEntry: QueueEntry): Promise<CommitConsensedTransactionResult> {
// Debug flag to intentionally skip committing account data
if (this.stateManager.debugFailToCommit) {
/* prettier-ignore */ if (logFlags.debug) this.mainLogger.debug(`debugFailToCommit active. Skipping commit for tx: ${queueEntry.logID}`)
queueEntry.accountDataSet = true
return { success: true }
}
let ourLockID = -1
let accountDataList: string | unknown[]
let uniqueKeys = []
Expand Down Expand Up @@ -6550,7 +6556,7 @@ class TransactionQueue {
try {
//This is a just in time check to make sure our involved accounts
//have not changed after our TX timestamp
const accountsValid = this.checkAccountTimestamps(queueEntry)
const accountsValid = await this.checkAccountTimestamps(queueEntry)
if (accountsValid === false) {
this.updateTxState(queueEntry, 'consensing')
queueEntry.preApplyTXResult = {
Expand Down Expand Up @@ -8388,7 +8394,7 @@ class TransactionQueue {
*
* @param queueEntry
*/
txWillChangeLocalData(queueEntry: QueueEntry): boolean {
async txWillChangeLocalData(queueEntry: QueueEntry): Promise<boolean> {
//if this TX modifies a global then return true since all nodes own all global accounts.
if (queueEntry.globalModification) {
return true
Expand All @@ -8414,7 +8420,7 @@ class TransactionQueue {

//if(queueEntry.localKeys[key] === true){
if (hasKey) {
const accountHash = this.stateManager.accountCache.getAccountHash(key)
const accountHash = await this.stateManager.accountCache.getAccountHash(key)
if (accountHash != null) {
// if the timestamp of the TX is newer than any local writeable keys then this tx will change local data
if (timestamp > accountHash.t) {
Expand All @@ -8435,15 +8441,15 @@ class TransactionQueue {
* timestamp newer than our transaction timestamp.
* If they do have a newer timestamp we must fail the TX and vote for a TX fail receipt.
*/
checkAccountTimestamps(queueEntry: QueueEntry): boolean {
async checkAccountTimestamps(queueEntry: QueueEntry): Promise<boolean> {
for (const accountID of Object.keys(queueEntry.involvedReads)) {
const cacheEntry = this.stateManager.accountCache.getAccountHash(accountID)
const cacheEntry = await this.stateManager.accountCache.getAccountHash(accountID)
if (cacheEntry != null && cacheEntry.t >= queueEntry.acceptedTx.timestamp) {
return false
}
}
for (const accountID of Object.keys(queueEntry.involvedWrites)) {
const cacheEntry = this.stateManager.accountCache.getAccountHash(accountID)
const cacheEntry = await this.stateManager.accountCache.getAccountHash(accountID)
if (cacheEntry != null && cacheEntry.t >= queueEntry.acceptedTx.timestamp) {
return false
}
Expand Down
Loading