XYOracleNetwork/sdk-core-nodejs

View on GitHub
src/simulation/index.ts

Summary

Maintainability
A
1 hr
Test Coverage
import { XyoZigZagBoundWitness } from '../bound-witness/xyo-zig-zag-bound-witness'
import { XyoBuffer, XyoStructure } from '../object-model'
import { XyoOriginState } from '../origin/xyo-origin-state'
import { XyoObjectSchema } from '../schema'
import { XyoRamOriginStateRepository } from './xyo-ram-origin-state-repository'
import { XyoStubSigner } from './xyo-stub-signature'

interface IXyoJsonBoundWitnessCreator {
  createBlocksFromJson(json: string): XyoZigZagBoundWitness[] | Error
}

export class XyoJsonBoundWitnessCreator implements IXyoJsonBoundWitnessCreator {
  private partyToState: Map<string, XyoOriginState> = new Map()

  // tslint:disable-next-line:prefer-array-literal
  public createBlockfromJson(boundWitness: {
    [key: string]: any
  }): XyoZigZagBoundWitness | undefined {
    const allKeys = Object.keys(boundWitness)
    if (allKeys.length > 2 || allKeys.length === 0) {
      throw new Error('Can only support two parties per BoundWitness')
    }
    if (allKeys.length === 2) {
      const alice = allKeys[0] as string
      const bob = allKeys[1] as string
      const aliceState = this.getPartyState(alice)
      const bobState = this.getPartyState(bob)

      const aliceHeuristics = this.createCustomHeuristicArrayWithDefaults(
        [],
        alice
      )
      const bobHeuristics = this.createCustomHeuristicArrayWithDefaults([], bob)

      const boundWitnessAlice = new XyoZigZagBoundWitness(
        aliceState.getSigners(),
        aliceHeuristics,
        []
      )
      const boundWitnessBob = new XyoZigZagBoundWitness(
        bobState.getSigners(),
        bobHeuristics,
        []
      )

      const aliceToBobOne = boundWitnessAlice.incomingData(undefined, false)
      const bobToAliceOne = boundWitnessBob.incomingData(aliceToBobOne, true)
      const aliceToBobTwo = boundWitnessAlice.incomingData(bobToAliceOne, false)
      boundWitnessBob.incomingData(aliceToBobTwo, false)

      aliceState.addOriginBlock(boundWitnessAlice)
      bobState.addOriginBlock(boundWitnessBob)
      return boundWitnessAlice
    }

    return this.createSelfSignedBoundWitness(allKeys[0])
  }

  public createBlocksFromJson(json: string): XyoZigZagBoundWitness[] {
    const bwArray: XyoZigZagBoundWitness[] = []
    const userData = JSON.parse(json) as Array<{ [key: string]: any }>

    userData.forEach((boundWitness) => {
      const cBw = this.createBlockfromJson(boundWitness)

      if (cBw) {
        bwArray.push(cBw)
      }
    })
    this.partyToState = new Map()
    return bwArray
  }

  private createSelfSignedBoundWitness(party: string): XyoZigZagBoundWitness {
    const charlieHeuristics = this.createCustomHeuristicArrayWithDefaults(
      [],
      party
    )
    const charlieState = this.getPartyState(party)
    const boundWitnessCharlie = new XyoZigZagBoundWitness(
      charlieState.getSigners(),
      charlieHeuristics,
      []
    )
    boundWitnessCharlie.incomingData(undefined, true)
    return boundWitnessCharlie
  }

  private createCustomHeuristicArrayWithDefaults(
    heuristics: { [key: string]: any },
    party: string
  ): XyoStructure[] {
    const desiredHeuristics = Object.keys(heuristics)
    const returnedHeuristics: XyoStructure[] = []
    desiredHeuristics.forEach((heuristic) => {
      const newHeuristic = this.createHeuristic(
        heuristic,
        heuristics[heuristic]
      )

      if (newHeuristic) {
        returnedHeuristics.push(newHeuristic)
      }
    })
    return this.appendNeededHeuristics(returnedHeuristics, party)
  }

  private createHeuristic(
    heuristic: string,
    value: number | string
  ): XyoStructure | undefined {
    switch (heuristic) {
      case 'rssi': {
        const numBuff = Buffer.alloc(1)
        numBuff.writeInt8(value as number, 0)
        const buffer = new XyoBuffer(numBuff)
        return XyoStructure.newInstance(XyoObjectSchema.RSSI, buffer)
      }
      case 'time': {
        const numBuff = Buffer.alloc(8)
        numBuff.writeUIntBE(value as number, 2, 6)
        const buffer = new XyoBuffer(numBuff)
        return XyoStructure.newInstance(XyoObjectSchema.UNIX_TIME, buffer)
      }
    }
  }

  private appendNeededHeuristics(
    heuristcs: any[],
    party: string
  ): XyoStructure[] {
    const state = this.getPartyState(party)
    if (!state) {
      return []
    }

    const hash = state.getPreviousHash()
    if (hash) {
      heuristcs.push(hash)
    }

    heuristcs.push(state.getIndex())
    return heuristcs
  }

  private getPartyState(party: string): XyoOriginState {
    let partyState = this.partyToState.get(party)
    if (!partyState) {
      const signer = new XyoStubSigner(Buffer.from(party))
      const stateRepo = new XyoRamOriginStateRepository()
      const state = new XyoOriginState(stateRepo)
      state.addSigner(signer)
      this.partyToState.set(party, state)
      partyState = this.partyToState.get(party)
    }
    return partyState as XyoOriginState
  }

  private setPartyState(party: string, state: XyoOriginState): void {
    this.partyToState.set(party, state)
  }
}