import { InstructionSetOperationMapping , Operation , } from '../../virtual-machine' ; import { AuthenticationProgramStateError , AuthenticationProgramStateExecutionStack , AuthenticationProgramStateStack , } from '../../vm-types' ; import { isScriptNumberError , parseBytesAsScriptNumber } from './common' ; import { applyError , AuthenticationErrorCommon } from './errors' ; export const incrementOperationCount = < State extends { operationCount : number ; } > ( operation ) : Operation < State > => ( state ) => { const nextState = operation ( state ) ; nextState . operationCount += 1 ; return nextState ; } ; export const conditionallyEvaluate = < State extends AuthenticationProgramStateExecutionStack > ( operation ) : Operation < State > => ( state ) => state . executionStack . every ( ( item ) => item ) ? operation ( state ) : state ; param operations param combinator export const mapOverOperations = < State > ( operations , ... combinators ) => Object . keys ( operations ) . reduce < { [ opcode ] : Operation < State > ; } > ( ( result , operation ) => ( { ... result , [ operation ] : combinators . reduce ( ( op , combinator ) => combinator ( op ) , operations [ parseInt ( operation , 10 ) ] ) , } ) , { } ) ; /**
 * Pop one stack item off of `state.stack` and provide that item to `operation`.
 */ export const useOneStackItem = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation ) => { const item = state . stack . pop ( ) ; if ( item === undefined ) { return applyError < State , Errors > ( AuthenticationErrorCommon . emptyStack , state ) ; } return operation ( state , [ item ] ) ; } ; export const useTwoStackItems = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation ) => useOneStackItem ( state , ( nextState , [ valueTwo ] ) => useOneStackItem ( nextState , ( lastState , [ valueTop ] ) => operation ( lastState , [ valueTop , valueTwo ] ) ) ) ; export const useThreeStackItems = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation ) => useOneStackItem ( state , ( nextState , [ valueThree ] ) => useTwoStackItems ( nextState , ( lastState , [ valueTop , valueTwo ] ) => operation ( lastState , [ valueTop , valueTwo , valueThree ] ) ) ) ; export const useFourStackItems = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation ) => useTwoStackItems ( state , ( nextState , [ valueThree , valueFour ] ) => useTwoStackItems ( nextState , ( lastState , [ valueTop , valueTwo ] ) => operation ( lastState , [ valueTop , valueTwo , valueThree , valueFour ] ) ) ) ; export const useSixStackItems = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation ) => useFourStackItems ( state , ( nextState , [ valueThree , valueFour , valueFive , valueSix ] ) => useTwoStackItems ( nextState , ( lastState , [ valueTop , valueTwo ] ) => operation ( lastState , [ valueTop , valueTwo , valueThree , valueFour , valueFive , valueSix , ] ) ) ) ; const normalMaximumScriptNumberByteLength = 4 ; export const useOneScriptNumber = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation , { requireMinimalEncoding , maximumScriptNumberByteLength = normalMaximumScriptNumberByteLength , } ) => useOneStackItem ( state , ( nextState , [ item ] ) => { const value = parseBytesAsScriptNumber ( item , { maximumScriptNumberByteLength , requireMinimalEncoding , } ) ; if ( isScriptNumberError ( value ) ) { return applyError < State , Errors > ( AuthenticationErrorCommon . invalidScriptNumber , state ) ; } return operation ( nextState , [ value ] ) ; } ) ; export const useTwoScriptNumbers = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation , { requireMinimalEncoding , maximumScriptNumberByteLength = normalMaximumScriptNumberByteLength , } ) => useOneScriptNumber ( state , ( nextState , [ secondValue ] ) => useOneScriptNumber ( nextState , ( lastState , [ firstValue ] ) => operation ( lastState , [ firstValue , secondValue ] ) , { maximumScriptNumberByteLength , requireMinimalEncoding } ) , { maximumScriptNumberByteLength , requireMinimalEncoding } ) ; export const useThreeScriptNumbers = < State extends AuthenticationProgramStateStack & AuthenticationProgramStateError < Errors > , Errors > ( state , operation , { requireMinimalEncoding , maximumScriptNumberByteLength = normalMaximumScriptNumberByteLength , } ) => useTwoScriptNumbers ( state , ( nextState , [ secondValue , thirdValue ] ) => useOneScriptNumber ( nextState , ( lastState , [ firstValue ] ) => operation ( lastState , [ firstValue , secondValue , thirdValue ] ) , { maximumScriptNumberByteLength , requireMinimalEncoding } ) , { maximumScriptNumberByteLength , requireMinimalEncoding } ) ; param state param data export const pushToStack = < State extends AuthenticationProgramStateStack > ( state , ... data ) => { state . stack . push ( ... data ) ; return state ; } ; export const combineOperations = < State > ( firstOperation , secondOperation ) => ( state ) => secondOperation ( firstOperation ( state ) ) ;