github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-supply-chain-master/server/scripts/run_sample_updates.js (about) 1 /** 2 * Copyright 2017 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 'use strict' 18 19 const _ = require('lodash') 20 const request = require('request-promise-native') 21 const protos = require('../blockchain/protos') 22 const { 23 awaitServerPubkey, 24 getTxnCreator, 25 submitTxns, 26 encodeTimestampedPayload 27 } = require('../system/submit_utils') 28 29 const SERVER = process.env.SERVER || 'http://localhost:3000' 30 const DATA = process.env.DATA 31 if (DATA.indexOf('.json') === -1) { 32 throw new Error('Use the "DATA" environment variable to specify a JSON file') 33 } 34 35 // How much random quantities can vary by 36 const VARIANCE_FACTOR = 0.75 37 38 // How many times to send each update per minute 39 // If 0, will send LIMIT updates immediately, then exit 40 const RATE = process.env.RATE ? Number(process.env.RATE) : 6 41 42 // Maximum number of times to repeat each update 43 const LIMIT = process.env.LIMIT ? Number(process.env.LIMIT) : 25 44 45 const updateGroups = require(`./${DATA}`) 46 let createTxn = null 47 48 const createUpdate = (privateKey, recordId, property) => { 49 return createTxn(privateKey, encodeTimestampedPayload({ 50 action: protos.SCPayload.Action.UPDATE_PROPERTIES, 51 updateProperties: protos.UpdatePropertiesAction.create({ 52 recordId, 53 properties: [protos.PropertyValue.create(property)] 54 }) 55 })) 56 } 57 58 const getVariance = max => { 59 if (typeof max === 'object') return _.mapValues(max, getVariance) 60 const variance = max * VARIANCE_FACTOR * Math.pow(Math.random(), 2) 61 return Math.random() < 0.5 ? -variance : variance 62 } 63 64 const updateValue = (update, oldValue) => { 65 if (typeof update.value === 'object') { 66 return _.mapValues(update.value, (value, key) => { 67 return updateValue(_.assign({}, update, { value }), oldValue[key]) 68 }) 69 } 70 71 let value = getVariance(update.value) 72 if (update.isAlwaysPositive) value = Math.abs(value) 73 if (update.isAverage) value = update.value + value 74 if (update.isRelative) value = oldValue + value 75 return value 76 } 77 78 const updateProperty = (update, oldValue) => { 79 oldValue = oldValue || update.startValue || null 80 const { NUMBER, LOCATION } = protos.PropertySchema.DataType 81 const property = _.pick(update, 'name', 'dataType') 82 83 if (property.dataType === NUMBER) { 84 property.numberValue = parseInt(updateValue(update, oldValue || 0)) 85 86 } else if (property.dataType === LOCATION) { 87 const defaultLoc = { latitude: 0, longitude: 0 } 88 const newLoc = updateValue(update, oldValue || defaultLoc) 89 const intLoc = _.mapValues(newLoc, parseInt) 90 91 if (intLoc.latitude > 90000000) intLoc.latitude = -90000000 92 else if (intLoc.latitude < -90000000) intLoc.latitude = 90000000 93 if (intLoc.longitude > 180000000) intLoc.longitude = -180000000 94 else if (intLoc.longitude < -180000000) intLoc.longitude = 180000000 95 96 property.locationValue = protos.Location.create(intLoc) 97 98 } else if (property.name === 'tilt') { 99 oldValue = JSON.parse(oldValue) 100 101 const defaultTilt = { x: 0, y: 0 } 102 const newTilt = updateValue(update, oldValue || defaultTilt) 103 const intTilt = _.mapValues(newTilt, parseInt) 104 105 property.stringValue = JSON.stringify(intTilt) 106 107 } else if (property.name === 'shock') { 108 oldValue = JSON.parse(oldValue) 109 110 const defaultShock = { accel: 0, duration: 0 } 111 const newShock = updateValue(update, oldValue || defaultShock) 112 const intShock = _.mapValues(newShock, parseInt) 113 114 property.stringValue = JSON.stringify(intShock) 115 116 } else { 117 throw new Error(`Bad update in JSON: ${property.name}`) 118 } 119 120 return property 121 } 122 123 const makeUpdateSubmitter = (count = 0) => () => { 124 if (count >= LIMIT) return 125 console.log(`Starting update set ${count + 1} of ${LIMIT}`) 126 // Get current property values 127 return request(`${SERVER}/records`) 128 .then(res => { 129 return JSON.parse(res).reduce((oldValues, record) => { 130 return _.assign({ 131 [record.recordId]: _.zipObject( 132 _.map(record.properties, prop => prop.name), 133 _.map(record.properties, prop => prop.value)) 134 }, oldValues) 135 }, {}) 136 }) 137 138 // Build update transactions 139 .then(oldValues => { 140 console.log(`Building updates . . .`) 141 return updateGroups.reduce((updateTxns, group) => { 142 group.updates.forEach(update => { 143 if (update.noOpChance && Math.random() < update.noOpChance) return 144 const oldValue = oldValues[group.recordId][update.name] 145 const prop = updateProperty(update, oldValue) 146 updateTxns.push(createUpdate(group.privateKey, group.recordId, prop)) 147 }) 148 return updateTxns 149 }, []) 150 }) 151 152 // Send update transactions 153 .then(updateTxns => { 154 console.log(`Submitting ${updateTxns.length} update transactions . . .`) 155 submitTxns(updateTxns) 156 }) 157 158 // Set timeout to call self 159 .then(() => { 160 console.log('Updates committed.') 161 const wait = RATE ? 60000 / RATE : 0 162 setTimeout(makeUpdateSubmitter(count + 1), wait) 163 }) 164 } 165 166 // Compile protos, fetch batcher pubkey, then begin submitting updates 167 protos.compile() 168 .then(awaitServerPubkey) 169 .then(batcherPublicKey => { 170 const txnCreators = {} 171 172 createTxn = (privateKey, payload) => { 173 if (!txnCreators[privateKey]) { 174 txnCreators[privateKey] = getTxnCreator(privateKey, batcherPublicKey) 175 } 176 return txnCreators[privateKey](payload) 177 } 178 }) 179 .then(() => makeUpdateSubmitter()()) 180 .catch(err => { 181 console.error(err.toString()) 182 process.exit() 183 })