github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/examples/intkey_javascript/integer_key_handler.js (about) 1 /** 2 * Copyright 2016 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * ------------------------------------------------------------------------------ 16 */ 17 18 'use strict' 19 20 const { TransactionHandler } = require('sawtooth-sdk/processor/handler') 21 const { 22 InvalidTransaction, 23 InternalError 24 } = require('sawtooth-sdk/processor/exceptions') 25 26 const crypto = require('crypto') 27 const cbor = require('cbor') 28 29 // Constants defined in intkey specification 30 const MIN_VALUE = 0 31 const MAX_VALUE = 4294967295 32 const MAX_NAME_LENGTH = 20 33 34 const _hash = (x) => 35 crypto.createHash('sha512').update(x).digest('hex').toLowerCase() 36 37 const INT_KEY_FAMILY = 'intkey' 38 const INT_KEY_NAMESPACE = _hash(INT_KEY_FAMILY).substring(0, 6) 39 40 const _decodeCbor = (buffer) => 41 new Promise((resolve, reject) => 42 cbor.decodeFirst(buffer, (err, obj) => (err ? reject(err) : resolve(obj))) 43 ) 44 45 const _toInternalError = (err) => { 46 let message = (err.message) ? err.message : err 47 throw new InternalError(message) 48 } 49 50 const _setEntry = (context, address, stateValue) => { 51 let entries = { 52 [address]: cbor.encode(stateValue) 53 } 54 return context.setState(entries) 55 } 56 57 const _applySet = (context, address, name, value) => (possibleAddressValues) => { 58 let stateValueRep = possibleAddressValues[address] 59 60 let stateValue 61 if (stateValueRep && stateValueRep.length > 0) { 62 stateValue = cbor.decodeFirstSync(stateValueRep) 63 let stateName = stateValue[name] 64 if (stateName) { 65 throw new InvalidTransaction( 66 `Verb is "set" but Name already in state, Name: ${name} Value: ${stateName}` 67 ) 68 } 69 } 70 71 // 'set' passes checks so store it in the state 72 if (!stateValue) { 73 stateValue = {} 74 } 75 76 stateValue[name] = value 77 78 return _setEntry(context, address, stateValue) 79 } 80 81 const _applyOperator = (verb, op) => (context, address, name, value) => (possibleAddressValues) => { 82 let stateValueRep = possibleAddressValues[address] 83 if (!stateValueRep || stateValueRep.length === 0) { 84 throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`) 85 } 86 87 let stateValue = cbor.decodeFirstSync(stateValueRep) 88 if (stateValue[name] === null || stateValue[name] === undefined) { 89 throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`) 90 } 91 92 const result = op(stateValue[name], value) 93 94 if (result < MIN_VALUE) { 95 throw new InvalidTransaction( 96 `Verb is ${verb}, but result would be less than ${MIN_VALUE}` 97 ) 98 } 99 100 if (result > MAX_VALUE) { 101 throw new InvalidTransaction( 102 `Verb is ${verb}, but result would be greater than ${MAX_VALUE}` 103 ) 104 } 105 106 // Increment the value in state by value 107 // stateValue[name] = op(stateValue[name], value) 108 stateValue[name] = result 109 return _setEntry(context, address, stateValue) 110 } 111 112 const _applyInc = _applyOperator('inc', (x, y) => x + y) 113 const _applyDec = _applyOperator('dec', (x, y) => x - y) 114 115 class IntegerKeyHandler extends TransactionHandler { 116 constructor () { 117 super(INT_KEY_FAMILY, ['1.0'], [INT_KEY_NAMESPACE]) 118 } 119 120 apply (transactionProcessRequest, context) { 121 return _decodeCbor(transactionProcessRequest.payload) 122 .catch(_toInternalError) 123 .then((update) => { 124 // 125 // Validate the update 126 let name = update.Name 127 if (!name) { 128 throw new InvalidTransaction('Name is required') 129 } 130 131 if (name.length > MAX_NAME_LENGTH) { 132 throw new InvalidTransaction( 133 `Name must be a string of no more than ${MAX_NAME_LENGTH} characters` 134 ) 135 } 136 137 let verb = update.Verb 138 if (!verb) { 139 throw new InvalidTransaction('Verb is required') 140 } 141 142 let value = update.Value 143 if (value === null || value === undefined) { 144 throw new InvalidTransaction('Value is required') 145 } 146 147 let parsed = parseInt(value) 148 if (parsed !== value || parsed < MIN_VALUE || parsed > MAX_VALUE) { 149 throw new InvalidTransaction( 150 `Value must be an integer ` + 151 `no less than ${MIN_VALUE} and ` + 152 `no greater than ${MAX_VALUE}`) 153 } 154 155 value = parsed 156 157 // Determine the action to apply based on the verb 158 let actionFn 159 if (verb === 'set') { 160 actionFn = _applySet 161 } else if (verb === 'dec') { 162 actionFn = _applyDec 163 } else if (verb === 'inc') { 164 actionFn = _applyInc 165 } else { 166 throw new InvalidTransaction(`Verb must be set, inc, dec not ${verb}`) 167 } 168 169 let address = INT_KEY_NAMESPACE + _hash(name).slice(-64) 170 171 // Get the current state, for the key's address: 172 let getPromise = context.getState([address]) 173 174 // Apply the action to the promise's result: 175 let actionPromise = getPromise.then( 176 actionFn(context, address, name, value) 177 ) 178 179 // Validate that the action promise results in the correctly set address: 180 return actionPromise.then(addresses => { 181 if (addresses.length === 0) { 182 throw new InternalError('State Error!') 183 } 184 console.log(`Verb: ${verb} Name: ${name} Value: ${value}`) 185 }) 186 }) 187 } 188 } 189 190 module.exports = IntegerKeyHandler