How can I return an array of struct in solidity? - algorithm

I am designing a solution for an ethereum smart contract that does bidding. The use-case includes reserving a name eg. "myName" and assigning to an address. And then, people can bid for that name (in this case myName). There can be multiple such biddings happening for multiple names.
struct Bid {
address bidOwner;
uint bidAmount;
bytes32 nameEntity;
}
mapping(bytes32 => Bid[]) highestBidder;
So, as you can see above, Bid struct holds data for one bidder, similarly, the key (eg. myName) in the mapping highestBidder points to an array of such bidders.
Now, I am facing a problem when I try to return something like highestBidder[myName].
Apparently, solidity does not support returning an array of structs (dynamic data). I either need to rearchitect my solution or find some workaround to make it work.
If you guys have any concerns regarding the question, please let me know, I will try to make it clear.
I am stuck here any help would be appreciated.

As you mentioned, this is not yet supported in Solidity. The powers that be are planning on changing it so you can, but for now, you have to retrieve the number of elements and then retrieve the decomposed struct as a tuple.
function getBidCount(bytes32 name) public constant returns (uint) {
return highestBidder[name].length;
}
function getBid(bytes32 name, uint index) public constant returns (address, uint, bytes32) {
Bid storage bid = highestBidder[name][index];
return (bid.bidOwner, bid.bidAmount, bid.nameEntity);
}
Edit to address question in comment regarding storage vs memory in this case
Local storage variables are pointers to state variables (which are always in storage). From the Solidity docs:
The type of the local variable x is uint[] storage, but since storage is not dynamically allocated, it has to be assigned from a state variable before it can be used. So no space in storage will be allocated for x, but instead it functions only as an alias for a pre-existing variable in storage.
This is referring to an example where the varable used is uint[] x. Same applies to my code with Bid bid. In other words, no new storage is being created.
In terms of cost:
getBid("foo", 0) using Bid memory bid:
getBid("foo", 0) using Bid storage bid:
In this case, storage is cheaper.

Return an array of struct in solidity?
In below function getBid returns array of bid structure.
contract BidHistory {
struct Bid {
address bidOwner;
uint bidAmount;
bytes32 nameEntity;
}
mapping (uint => Bid) public bids;
uint public bidCount;
constructor() public {
bidCount = 0;
storeBid("address0",0,0);
storeBid("address1",1,1);
}
function storeBid(address memory _bidOwner, uint memory _bidAmount, bytes32 memory _nameEntity) public {
bids[tripcount] = Bid(_bidOwner, _bidAmount,_nameEntity);
bidCount++;
}
//return Array of structure
function getBid() public view returns (Bid[] memory){
Bid[] memory lBids = new Bid[](tripcount);
for (uint i = 0; i < bidCount; i++) {
Bid storage lBid = bids[i];
lBids[i] = lBid;
}
return lBids;
}
}

About "returning an array of structs"... just a small workaround in order to return an array of structs extracted from medium
pragma solidity ^0.4.13;
contract Project
{
struct Person {
address addr;
uint funds;
}
Person[] people;
function getPeople(uint[] indexes)
public
returns (address[], uint[]) {
address[] memory addrs = new address[](indexes.length);
uint[] memory funds = new uint[](indexes.length);
for (uint i = 0; i < indexes.length; i++) {
Person storage person = people[indexes[i]];
addrs[i] = person.addr;
funds[i] = person.funds;
}
return (addrs, funds);
}
}
The uint[] index parameters should contain the indexes that you want to access.
Best

Related

Transferring assets between accounts and pallet

I'm trying to create a pallet that users can deposit assets into and withdraw from.
I've written the following code, but I'm not sure it's the best way to about things due to frame_system::RawOrigin::Root.into() being accessible by every runtime.
I'm still fairly new to Substrate and not sure this is exactly how it works, would love some guidance on the best design choice.
Making use of assets pallet to deposit:
<Assets::Module<T>>::transfer(origin, asset_id, RawOrigin::Root.into(), amount);
To Withdraw:
<Assets::Module<T>>::transfer(RawOrigin::Root.into(), asset_id, origin, amount);
Edit
A similar idea written in Solidity:
contract DepositWithdrawSend {
using SafeMath for uint256;
mapping (address => mapping (address => uint256)) public depositInfo;
address public sendPallet;
constructor(address _sendPallet) public {
sendPallet = _sendPallet;
}
function deposit(address _token, uint256 _amount) public {
IERC20(_token).transferFrom(msg.sender, address(this), amount);
depositInfo[_token][msg.sender] = depositInfo[_token][msg.sender].add(_amount);
}
function withdraw(address _token, uint256 _amount) public {
require(depositInfo[_token][msg.sender] >= _amount, "Over withdraw");
require(IERC20(_token).balanceOf(address(this)) >= _amount, "Not enough");
IERC20(_token).transfer(msg.sender, amount);
depositInfo[_token][msg.sender] = depositInfo[_token][msg.sender].sub(_amount);
}
function send(address _token, uint256 _amount) public {
require(IERC20(_token).balanceOf(address(this)) >= _amount, "Not enough");
IERC20(_token).transfer(sendPallet, amount);
}
}
We follow a pretty simple pattern to give pallets their own "account" for transferring balances to or anything else.
First you create a unique PalletId representing your pallet:
use frame_support::PalletId;
const MyPalletId: PalletId = PalletId(*b"replace_");
Then from here, you can generate an AccountId from this PalletId:
use sp_runtime::traits::AccountIdConversion;
/// These actually do computation. If you need to keep using them,
/// then make sure you cache the value and only call them once.
pub fn account_id() -> T::AccountId {
T::PalletId::get().into_account()
}
pub fn sub_account(seed: u16) -> T::AccountId {
// only use two byte prefix to support 16 byte account id (used by test)
// "modl" ++ "replace_" ++ "hi" is 14 bytes, and two bytes remaining for bounty index
T::PalletId::get().into_sub_account(("hi", id))
}
This pattern is used in the Treasury Pallet and others.

A algorithm to track the status of a number

To design a API,
get(), it will return the random number, also the number should not duplicate, means it always be unique.
put(randomvalue), it will put back the generated random number from get(), if put back, get() function can reuse this number as output.
It has to be efficient, no too much resource is highly used.
Is there any way to implement this algorithm? It is not recommended to use hashmap, because if this API generate for billions of requests, saving the generated the random number still use too much space.
I could no work out this algorithm, please help give a clue, thanks in advance!
I cannot think of any solution without extra space. With space, one option could be to use TreeMap, firstly add all the elements in treeMap with as false. When element is accessed, mark as true. Similarly for put, change the value to false.
Code snippet below...
public class RandomNumber {
public static final int SIZE = 100000;
public static Random rand;
public static TreeMap<Integer, Boolean> treeMap;
public RandomNumber() {
rand = new Random();
treeMap = new TreeMap<>();
}
static public int getRandom() {
while (true) {
int random = rand.nextInt(SIZE);
if (!treeMap.get(random)) {
treeMap.put(random, true);
return random;
}
}
}
static public void putRandom(int number) {
treeMap.put(number, false);
}
}

Custom comparator for a priority queue without defining a nested class

I have a class called getout (no constructor). Within that class I have some private variables that are priority queues. The priority queues are initialized with a custom comparator function that I am supposed to create:
priority_queue<tile, vector<tile>, ****insert comparator here***> primary;
I understand that custom comparators can be written using a class or struct. However I cannot do it this way (Im sure there's a way). The reason why is within this comparator I use functions pertaining to my class getout. I decided to write my comparator as a regular bool function as follows:
class escape{
public:
//grabs row of the tile
int get_row(int index){
return floor(index/size);
}
//grabs column of the tile
int get_col(int index){
return index - get_row(index)*size;
}
//stores information about each tile of the grid
struct tile{
int index;
};
//returns the index provided a row and column
int get_index(int row, int col){
return row*size + col;
}
//comparator less_than
bool less_than(const tile &t1, const tile &t2)
{
if(t1.rubble_amount == t2.rubble_amount){
//return object with lower column value
if(get_col(t1.index) == get_col(t2.index)){
return get_row(t1.index) > get_row(t2.index);
}
//if column values are same, return object with lower row
else if(get_col(t1.index) > get_col(t2.index)){
return true;
}
}//if
return t1.rubble_amount > t2.rubble_amount;
}//comparator less_than
};
The functions pertaining to my class I am using are get_row(), get_col(). I do not want to resolve this by making them member variables of my tile structs.
How do I define the comparator of my priority queue that is of the form of a bool function?
Everything is in my class getout.
I have tried:
priority_queue<tile, vector<tile>, function<bool(tile, tile)>> primary(less_than);
But I am getting an error "Unknown type name less_than". Am I implementing the above code correctly ? Is there another way I can do this?
(all necessary libraries are included)
Thanks!!

Use hashCode() for sorting Objects in java, not in HashTable and ect

I need your help.
If i want to sort a PriorityQeueu in java, with out connection to it's attributes - could i use the hashCode's Objects to compare?
This how i did it:
comp = new Comparator<Person>() {
#Override
public int compare(Person p1, Person p2) {
if(p1.hashCode() < p2.hashCode()) return 1;
if(p1.hashCode() == p2.hashCode()) return 0;
return -1;
}
};
collector = new PriorityQueue<Person>(comp);
It doesn't sound like a good approach.
Default hashCode() is typically implemented by converting the internal address of the object into an integer. So the order of objects will differ between application executions.
Also, 2 objects with the same set of attribute values will not return the same hashCode value unless you override the implementation. This actually breaks the expected contract of Comparable.

Boost posix time

I have a very strange problem now.
class Message
{
Field time;
void SetTimeStamp()
{
time.dataTimeValue = &boost::posix_time::microsec_clock::universal_time();
}
void SetOtherFields()
{
}
};
class Field
{
boost::posix::ptime* dateTimeValue;
};
int main()
{
Message myMessage;
myMessage.SetTimeStamp();
myMessage.SetOtherFields();
}
When I call myMessage.SetTimeStamp(), I can set the TimeStamp correctly, I can see the address of dateTimeValue and the Value makes sense. But after that, I call myMessage.SetOtherFields(), the dateTimeValue pointer still points to the same memory which is good, but the value in that memory changes to a carzy number. I don't know what happened.
A decent compiler should have warned that the code is taking address of temporary. The microsec_clock::local_time() function returns ptime by value, resulting in Message::SetTimeStamp storing the address of the temporary into Field::dateTimeValue. Trying to access the values of the memory will result in undefined behavior.
To resolve this, consider changing Field to aggregate a boost::posix::ptime member variable, rather than a pointer.
class Field
{
public:
boost::posix_time::ptime dateTimeValue;
};
class Message
{
public:
Field time;
void SetTimeStamp()
{
time.dataTimeValue = boost::posix_time::microsec_clock::universal_time();
}
};

Resources