Send Signed Transaction for Contract Interaction on Quorum using web3js - solidity

I am currently running the 7 nodes example given in quorum-examples github repo. I have deployed a very simple storage contract which gets and sets the value. As per the example, I am able to interact with the smart contract inside the geth node cmd line. However I would like to interact with it using another address outside the node and so I wrote the following code:
const Web3 = require('web3')
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:22000'))
const { Transaction } = require('#ethereumjs/tx')
const { default: Common } = require('#ethereumjs/common')
const run = async () => {
const contractInstance = await new web3.eth.Contract(
[
{
constant: true,
inputs: [],
name: 'storedData',
outputs: [{ name: '', type: 'uint256' }],
payable: false,
type: 'function',
},
{
constant: false,
inputs: [{ name: 'x', type: 'uint256' }],
name: 'set',
outputs: [],
payable: false,
type: 'function',
},
{
constant: true,
inputs: [],
name: 'get',
outputs: [{ name: 'retVal', type: 'uint256' }],
payable: false,
type: 'function',
},
{
inputs: [{ name: 'initVal', type: 'uint256' }],
payable: false,
type: 'constructor',
},
],
'0xd9d64b7dc034fafdba5dc2902875a67b5d586420'
)
const customCommon = Common.forCustomChain('mainnet', {
chainId: 10,
})
const txCount = await web3.eth.getTransactionCount(
'ed9d02e382b34818e88b88a309c7fe71e65f419d'
)
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: '0x47b760',
gasPrice: '0x00',
value: '0x0',
chainId: 10,
to: '0xd9d64b7dc034fafdba5dc2902875a67b5d586420',
data: contractInstance.methods.set(10).encodeABI(),
}
const tx = Transaction.fromTxData(txData, { common: customCommon })
const signedTx = tx.sign(
Buffer.from(
'e6181caaffff94a09d7e332fc8da9884d99902c7874eb74354bdcadf411929f1',
'hex'
)
)
const serializedTx = signedTx.serialize()
const result = await web3.eth.sendSignedTransaction(
`0x${serializedTx.toString('hex')}`
)
return result
}
run().then(console.log).catch(console.log)
However whenever I try to send the transtion, it always errors out to
"Transaction has been reverted by the EVM:\n{\n \"blockHash\": \"0xd6b06321882912185f5e1d3401a012f58b6bbf7eee1e1d2c6c2cd80a0e13bbdc\",\n \"blockNumber\": 5,\n \"contractAddress\": null,\n \"cumulativeGasUsed\": 23751,\n \"from\": \"0x0fbdc686b912d7722dc86510934589e0aaf3b55a\",\n \"gasUsed\": 23751,\n \"logs\": [],\n \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n \"status\": false,\n \"to\": \"0x9d13c6d3afe1721beef56b55d303b09e021e27ab\",\n \"transactionHash\": \"0x8c7fd175ab037e24e531804774e8b89bf5aea25de8d99aa9bc2c034229603299\",\n \"transactionIndex\": 0\n}",
Do let me know if more info is required and I will update the post.
The smartcontract code is as follows:
pragma solidity ^0.5.0;
contract simplestorage {
uint public storedData;
constructor(uint initVal) public {
storedData = initVal;
}
function set(uint x) public {
storedData = x;
}
function get() view public returns (uint retVal) {
return storedData;
}
}

I think i met the similar issue as well. My issue was invalid chain id signer. I checked many docs and tried to set the custom chain id which was what you did about "common". But nothing changed until i changed the version of ethereumjs-tx to ^1.3.7. btw you dont need common if you try my solution.

Related

Error: Exception in HostFunction: Attempting to create an object of type 'sets' with an existing primary key value '6' in react native

I'm trying to store history of workout in realm, my addHistory function looks like this
export function addHistory(workout, exercise, sets, _id) {
console.log({
workout,
exercise,
sets,
_id,
});
if (
_id !== undefined &&
workout !== undefined &&
exercise !== undefined &&
sets !== undefined
) {
// return console.log("HISTORY ", { workout, exercise, sets, _id });
return realm.write(() => {
return realm.create("workoutData", {
_id: _id,
exercise,
workout,
sets,
workoutDate: new Date(Date.now()),
});
});
} else {
alert("History is incomplete");
}
}
Schema of the workoutData is as follows:
exports.workoutData = {
name: "workoutData",
primaryKey: "_id",
properties: {
_id: "int",
workout: "workouts",
exercise: "exercise",
workoutDate: "date",
sets: "sets[]",
},
};
Now when I add sets and click on finishWorkoutHandler the logic works fine before the addHistory function but when addHistory is executed it throws the error as stated in the question.
//finish workout handler
const finishWorkoutHandler = () => {
if (sets.length == 0) {
return;
}
let setsFromRealm = realm.objects("sets");
let workoutData = realm.objects("workoutData");
let setsArray = [];
exercises.forEach((exercise) => {
sets
.filter((items) => items.exercise._id == exercise._id)
.forEach((sets) => {
let _id = 0;
if (setsFromRealm.length > 0) {
_id = realm.objects("sets").max("_id") + 1;
}
addSet(
sets.name,
parseInt(sets.weight),
parseInt(sets.reps),
parseInt(sets.rmValue),
sets.isHeighest,
sets.exercise,
_id,
sets.profile,
sets.failedSet,
sets.warmupSet,
sets.notes
);
let indiSet = {
name: sets.name,
weight: parseInt(sets.weight),
reps: parseInt(sets.reps),
rmValue: parseInt(sets.rmValue),
isHeighest: sets.isHeighest,
_id: _id,
profile: sets.profile,
failedSet: sets.failedSet,
warmupSet: sets.warmupSet,
notes: sets.notes,
createdDate: new Date(Date.now()),
};
setsArray.push(indiSet);
});
let workoutDataId = 0;
let setsArrcopy = setsArray;
console.log("SETS ", realm.objects("sets"));
console.log("SETS ", setsArrcopy);
if (workoutData.length > 0) {
workoutDataId = realm.objects("workoutData").max("_id") + 1;
}
**WORKING AS EXPECTED TILL HERE**
// problem lies here
addHistory(params.workout, exercise, setsArrcopy, workoutDataId);
});
dispatch(setsEx([]));
goBack();
};
the structure of setsArrCopy containing sets is as follows
[
({
_id: 6,
createdDate: 2022-09-29T16:27:06.128Z,
failedSet: false,
isHeighest: false,
name: "Thai",
notes: "",
profile: [Object],
reps: 12,
rmValue: 64,
warmupSet: false,
weight: 56,
},
{
_id: 7,
createdDate: 2022-09-29T16:27:06.151Z,
failedSet: false,
isHeighest: false,
name: "Thsi 3",
notes: "",
profile: [Object],
reps: 10,
rmValue: 75,
warmupSet: false,
weight: 66,
})
];
the logic is also working fine in terms of assigning new ids to the sets being added in a loop. But somehow its throwing error when passing setArrCopy to addHistory function. Although its an array of sets not a single object?

Undefined is not an object using react native realm

I want to build an application using react native and implement realm. It is meant to have some playlists and songs, and the songs should be able to be added to the playlists.
Playlist:
export class Playlist {
public id: number;
public name: string;
public color: string;
public songs: Song[];
constructor(id: number, name: string, color: string, songs: Song[]) {
this.id = id;
this.name = name;
this.color = color;
this.songs = songs;
}
static schema: Realm.ObjectSchema = {
name: 'Playlist',
primaryKey: 'id',
properties: {
id: 'int',
name: 'string',
color: 'string',
songs: 'Song[]',
},
};
}
Song:
export class Song {
public id: number;
public title: string;
public artist: string;
constructor(id: number, title: string, artist: string) {
this.id = id;
this.title = title;
this.artist = artist;
}
static schema: Realm.ObjectSchema = {
name: 'Song',
primaryKey: 'id',
properties: {
id: 'int',
title: 'string',
artist: 'string',
},
};
}
Realm:
const initData = () => {
const songs = [
new Song(0, 'Avicii', 'Heaven'),
// some songs
];
const playlists = [
new Playlist(0, 'Favorite Songs', 'purple', []),
// some playlists
];
songs.forEach(song => {
Song.insertSong(song);
});
playlists.forEach(playlist => {
Playlist.insertPlaylist(playlist);
});
};
const databaseOptions = {
path: 'playlists.realm',
schema: [Playlist.schema, Song.schema],
};
let realmInstance: Realm | null;
const getRealm = (): Realm => {
if (realmInstance == null) {
realmInstance = new Realm(databaseOptions);
initData();
}
return realmInstance!;
};
export default getRealm;
I always get the error:
TypeError: undefined is not an object (evaluating '_playlist.Playlist.schema')
And I can't figure out why. If you need more code, just tell me.
I am new to react native and JavaScript and TypeScript. I am used to developing Android apps using Java, so maybe I did some dumb mistakes, I don't know.
You are not using your real instance in initData, you need to use realm.write like in the below example. I think my little piece of code should works update me what u got(its better to use Realm async than sync as you want)
const PersonSchema = {
name: 'Person',
properties: {
// The following property definitions are equivalent
cars: {type: 'list', objectType: 'Car'},
vans: 'Car[]'
}
}
let carList = person.cars;
// Add new cars to the list
realm.write(() => {
carList.push({make: 'Honda', model: 'Accord', miles: 100});
carList.push({make: 'Toyota', model: 'Prius', miles: 200});
});
let secondCar = carList[1].model; // access using an array index
In your case
Realm.open({schema: [Song, PlayList]})
.then(realm => {
// ...use the realm instance here
try {
realm.write(() => {
const songs = [
realm.create('Song',{title: 'Avicii', artist: 'Heaven'}),
];
const playlists = [
realm.create('Playlist',{name: 'Favorite Songs', color: 'purple', songs: []}),
// some playlists
];
playlists.forEach(playlist => {
for (const song of songs){
playlist.songs.push(song);
}
});
});
} catch (e) {
console.log("Error on creation");
}
})
.catch(error => {
// Handle the error here if something went wrong
});

Vuejs: Cannot set property 'profile_picture' of undefined

I'm really confused whats wrong with my code. Can someone tell me what I did wrong here.
data() {
return {
users: [],
}
},
methods:{
moveData(response){
for(var x=0;x<response.data.data.length; x++){
this.users[x].profile_picture = response.data.data[x].profile_picture;
this.users[x].age = response.data.data[x].age;
this.users[x].intro = response.data.data[x].introMessage;
this.users[x].name = response.data.data[x].userName;
}
// eslint-disable-next-line
console.log('Users',this.users);
}
}
as the error suggests that this.users[x] is undefined. the simple solution would be to initialize this.users[x] with some empty object just like
for(var x=0;x<response.data.data.length; x++){
this.users[x] = {};
this.users[x].profile_picture = response.data.data[x].profile_picture;
this.users[x].age = response.data.data[x].age;
this.users[x].intro = response.data.data[x].introMessage;
this.users[x].name = response.data.data[x].userName;
}
As you using this.users[x], it always undefined because your array length is 0. So here one way more you can use .map() array to modify the field name and directly assign response to your users in moveData.
By use of Map array with spread operator
const response = [{
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 25,
introMessage: 'Hello',
userName: 'test105'
}, {
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 18,
introMessage: 'HI',
userName: 'demo105'
}]
console.log(response.map(({age,profile_picture,...r}) => Object.create({
age,
profile_picture,
name: r.userName,
intro: r.introMessage
})));
Modification in your code, use push method of array
const response = {
data: {
data: [{
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 25,
introMessage: 'Hello',
userName: 'test105'
}, {
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 18,
introMessage: 'HI',
userName: 'demo105'
}]
}
}
let users = [];
for (var x = 0; x < response.data.data.length; x++) {
users.push({
profile_picture: response.data.data[x].profile_picture,
age: response.data.data[x].age,
intro: response.data.data[x].introMessage,
name: response.data.data[x].userName
});
}
console.log(users)

Keystone.js filtering on related fields within own model

I am working on filtering my subsection selection to display only subSections that are related to the current mainNavigationSection. Each of these subsections also has a mainNavigation section. For some reason the current implementation is not returning any results.
Here is my Page Model:
Page.add({
name: { type: String, required: true },
mainNavigationSection: { type: Types.Relationship, ref: 'NavItem', refPath: 'key', many: true, index: true },
subSection: { type: Types.Relationship, ref: 'SubSection', filters: { mainNavigationSection:':mainNavigationSection' }, many: true, index: true, note: 'lorem ipsum' },
state: { type: Types.Select, options: 'draft, published, archived', default: 'draft', index: true },
author: { type: Types.Relationship, ref: 'User', index: true }
}
Here is my subSectionModel:
SubSection.add({
name: { type: String, required: true, index: true },
mainNavigationSection: { type: Types.Relationship, ref: 'NavItem', many: true, required: true, initial: true},
showInFooterNav: { type: Boolean, default: false },
defaultPage: { type: Types.Relationship, ref: 'Page' },
description: { type: Types.Html, wysiwyg: true, height: 150, hint: 'optional description' }
});
From what it seems, you have the possibility of many mainNavigationSections on your model. You'd have to iterate over each of them on the current Page, and find the related SubSections. You'll need to use the async Node module to run all the queries and get the results from each.
var async = require('async');
var pID = req.params.pid; // Or however you are identifying the current page
keystone.list('Page').model.findOne({page: pID}).exec(function (err, page) {
if (page && !err) {
async.each(page.mainNavigationSection, function (curMainNavigationSection, cb) {
keystone.list('SubSection').model
.find({mainNavigationSection: curMainNavigationSection._id.toString()})
.exec(function (err2, curSubSections) {
if (curSubSections.length !== 0 && !err2) {
// Do what you need to do with the navigation subSections here
// I recommend using a local variable, which will persist through
// every iteration of this loop and into the callback function in order
// to persist data
return cb(null)
}
else {
return cb(err || "An unexpected error occurred.");
}
});
}, function (err) {
if (!err) {
return next(); // Or do whatever
}
else {
// Handle error
}
});
}
else {
// There were no pages or you have an error loading them
}
});

Mongoose's populate method breaks promise chain?

So I have a mongoose Schema that looks like this:
var Functionary = new Schema({
person: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Person'
},
dateOfAssignment: Date,
dateOfDischarge: Date,
isActive: Boolean
});
var PositionSchema = new Schema({
name: String,
description: String,
maxHeadCount: Number,
minHeadCount: Number,
currentHeadCount: Number,
currentlyHolding: [Functionary],
historical: [Functionary],
responsibleTo: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Position'
}
});
*note that the Position document can reference itself in the ResponsibleTo field.
Now, I'm trying to build a method that will search the Positions collection, populate the currentlyHolding[].person.name field and the responsibleTo.currentlyHolding[].person.name field, and also return the total number of records found (for paging purposes on the front-end).
Here's what my code looks like:
exports.search = function(req, res) {
var result = {
records: null,
count: 0,
currentPage: req.params.page,
totalPages: 0,
pageSize: 10,
execTime: 0
};
var startTime = new Date();
var populateQuery = [
{
path: 'currentlyHolding.person',
select: 'name'
}, {
path:'responsibleTo',
select:'name currentlyHolding.person'
}
];
Position.find(
{
$or: [
{ name: { $regex: '.*' + req.params.keyword + '.*', $options: 'i' } },
{ description: { $regex: '.*' + req.params.keyword + '.*', $options: 'i' } }
]
},
{},
{
skip: (result.currentPage - 1) * result.pageSize,
limit: result.pageSize,
sort: 'name'
})
.exec()
.populate(populateQuery)
.then(function(doc) {
result.records = doc;
});
Position.count(
{
$or: [
{ name: { $regex: '.*' + req.params.keyword + '.*', $options: 'i' } },
{ description: { $regex: '.*' + req.params.keyword + '.*', $options: 'i' } }
]
})
.exec()
.then(function(doc) {
result.count = doc;
result.totalPages = Math.ceil(result.count / result.pageSize);
})
.then(function() {
var endTime = new Date();
result.execTime = endTime - startTime;
return res.json(200, result);
});
};
My problem is when I run the first query with the populate method (as is shown), it doesn't work. I take away the populate and it works. Is it true that the populate method will break the promise? If so, are there better ways to achieve what I want?
It's been a while since you asked, but this might still help others so here we go:
According to the docs, .populate() doesn't return a promise. For that to happen you should chain .execPopulate().
Alternatively, you can put .populate() before .exec(). The latter will terminate the query builder interface and return a promise for you.