what is storage slot in forge-std and how to set specific number for it? - unit-testing

I'm try to write smart contract based on forge-std, and writing some test by solidity looks like this:
function testOutOfToken() public {
vm.store(
address(nftToken),
bytes32(uint256(7)),
bytes32(uint256(10000))
);
vm.expectRevert(abi.encodeWithSignature("MaxSupplyReached()"));
nftToken.mintNft{value: 0.15 ether}(1);
}
the second parameter is bytes32(uint256(7)), from the document is explained like this:
// Stores a value to an address' storage slot, (who, slot, value)
function store(address,bytes32,bytes32) external;
but I still don't understand what storage slot is, if I change the 7 to some other number like 8, the test won't pass. Any idea? Thanks!

Each property of a contract can have some value, and the value is stored in a predetermined location - in a predetermined slot.
For 256bit scalar types, the slot ID is calculated simply by the property position in the code. Smaller types are packed into the same slot (used to be separate in older Solidity versions). And dynamic types are located in slots determined by a hash.
Docs: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
pragma solidity ^0.8;
contract MyContract {
uint256 numberA = 1; // slot 0
uint256 numberB = 1; // slot 1
uint256 numberC = 1; // slot 2
uint128 numberD = 1; // slot 3
uint128 numberE = 1; // slot 3
// length in slot 4
// values in slot ID determined by hash of the position + offset
// in this case keccak256(4) + 0, keccak256(4) + 1, and keccak256(4) + 2
uint256[] numbers;
constructor() {
numbers.push(2);
numbers.push(3);
numbers.push(4);
}
}
if I change the 7 to some other number like 8, the test won't pass
Most likely the value that your test is checking against, is stored in slot ID 7. And slot ID 8 contains some other value (or the default value of 0). Since the other slot doesn't contain the expected value, the test fails.

Related

Called function suddenly needs to be payable

I have a public uint variable denoting 'which round' it is and a function that advances rounds and does processing alongside the round advancement:
uint public round;
function completeRound() public inPaused() inRound() {
if (round == 6) {
// win
} else {
reduceByHalf();
round.add(1);
}
}
If i run this in remix, it runs 4 times and then consistently fails on the 5th, indicating that a function suddenly needs to be payable:
transact to Playingwithsmartcontracts.completeRound errored: VM error: revert. revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.
If I comment out round.add(1) right under where reduceByHalf is called, the code works all day long. I can click it indefinitely with no errors in Remix.
Strangely, this started as an Enum to track the rounds and that had the same exact problem. While advancing the enum, i could do it 5 times before the above failure and commenting it out made everything work.
reduceByHalf code doesnt seem to be the offender, but it is shown below in case it has a bearing on the problem:
struct Foo {
address owner;
uint mintedRound;
uint winningRound;
}
struct FooOwner {
uint[] foos;
uint totalWinningFoos;
}
uint[][5] roundFoos;
uint[][5] roundWinners;
mapping(uint => Foo) public winningFoos;
mapping(address => FooOwner) public fooOwners;
uint totalWinningFoos;
function shuffleFoos (uint256[] memory _array) internal view returns(uint[] memory){
uint[] memory clone = cloneArray(_array, _array.length);
for (uint256 i = 0; i < clone.length; i++) {
uint256 n = i + uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp))) % (clone.length - i);
uint256 temp = clone[n];
clone[n] = clone[i];
clone[i] = temp;
}
return clone;
}
function cloneArray(uint256[] memory _array, uint256 _length) internal pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](_length);
for (uint256 i = 0; i < _length; i++) {
array[i] = _array[i];
}
return array;
}
function reduceByHalf() internal {
uint[] memory clone = shuffleFoos(roundFoos[round]);
uint halfLength = 0;
halfLength = roundFoos[round].length.div(2);
for (uint w = 0; w < halfLength; w++) {
uint fooId = clone[w];
roundWinners[round].push(fooId);
winningFoos[round].winningRound = round;
address fooOwner = winningFoos[fooId].owner;
fooOwners[fooOwner].totalWinningFoos = fooOwners[fooOwner].totalWinningFoos.add(1);
}
totalWinningFoos = totalWinningFoos.add(halfLength);
}
As far as I know, I am not sending value, and not sure why it only thinks im sending value on transaction execution 5.
Would anyone be able to help me understand what Remix/Solidity is mad about?
I totally must not be understanding somehthing but it looks like it's something about the number 5... I can advance the round to 6, but as soon as I set the uint value to 5 is when I start seeing these problems.... so wierd....
The transaction has been reverted to the initial state.
This is the important part of the error message in your case.
Note: The called function should be payable if you send value
This is just a note, possibly because this combination often happens. But since your function and transaction doesn't send any value, it doesn't apply to your case.
round.add(1);
This (failing) snippet suggests, that there's supposed to be a library used for uint, but it's not defined. I'm gonna go with the SameMath library, because of the .add() function name and the use on uint. But in theory, it could be any library, SafeMath is just the most probable option in this context.
Mind that round.add(1); (using SafeMath) returns the value of round incremented by 1, but it doesn't store the (incremented) value anywhere. This looks like a typo and the real usage should be round = round.add(1);
Your code doesn't show any usage of the SafeMath library, but also doesn't show the Solidity version, so I'm going to divide my answer into 3 parts.
You're using Solidity 0.8+.
SameMath is not needed, because integer overflow is handled on a lower level, and you can safely replace
// even with correctly imported SafeMath, it doesn't update the stored value
round.add(1);
to
// updates the stored value
round++;
You're using Solidity 0.7 or older, and SafeMath for uint256 (not uint)
Change the definition
uint public round;
to
uint256 public round;
This way, SafeMath will be used for round and it will allow to use the function .add().
Mind that you might want to also store the incremented value, see the bold paragraph with example above.
You're using Solidity 0.7 or older, and not using SafeMath at all.
You need to import the SafeMath library and then make changes described in the point 2.

Creating a reduce function that ignores children of a node

I have a set of documents in couch DB that act as a tree. Each document includes an ancestors field that includes a list of IDs that represent the location in the tree of the current document. Some of the documents have a value associated with them (a number).
When a document does not have it's own value, it's implicit value is the maximum of all of it's children. But when a document does have it's own value, the value of any children is ignored. For example
Root (no value, no ancestors) effective value 7
Child1 (value 5, ancestors= Root) effective value 5
Grandchild1 (value 9, ancestors=Root,Child1) effective value 9
Child2 (no value, ancestors= Root) effective value 7
Grandchild2 (value 3, ancestors=Root,Child2) effective value 3
Grandchild3 (value 7, ancestors=Root,Child2) effective value 7
Child3 (value 6, ancestors= Root) effective value 6
I'm trying to build a view that allows me to get the effective value for a given node (I will have the full path so could key by path or id). So what I'm trying doing is:
Emit anything that has an explicit value in my map function
Build a reduce function that returns the explicit value for a node if it has one or finds the maximum of it's children if it doesn't.
I'm struggling to make this work because reduce appears to be run on partitions of the data. So I keep getting scenarios where the child and parent don't come together until a re-reduce so I lose the relationships and get the wrong value. e.g. with the above tree:
Grandchild 1 (value 9) and Grandchild 3 (value 7) end up on the same partition so are reduced first, resulting in value 9
Child 1 (value 5) is reduced with Child 3 (value 6) resulting in 6 being the winning value and dropping any knowledge of Child 1
The re-reduce happens to reduce Child 3 (value 6) and Grandchild 1 (value 9) and the resulting value is 9, because Child 1 is not involved in this reduce we don't know that the 9 should actually be replaced by a 5 so we get the wrong result.
Is it possible to implement this logic in a couch view reduce function?
My current implementations are:
Map Function
function (doc) {
if (doc.ancestors && doc.data) {
// For anything with a value emit it with the full path as the key
var path = doc.ancestors.concat([doc._id]);
emit(path, {data: doc.data, path: path})
}
}
Reduce Function
function (keys, values, rereduce) {
// build a tree of the values currently being reduced
// by reassembling the paths and putting the value
// at the targeted location
var tree = {children: {}};
function addValueToTree(value) {
var parent = tree;
value.path.forEach(function(docId) {
var newParent = parent.children[docId] || {children: {}};
parent.children[docId] = newParent;
parent = newParent;
});
parent.value = value;
}
values.forEach(addValueToTree);
// Object.entries isn't supported in Couch JS
// engine so simple polyfill
function entries(obj) {
var entries = [];
for (k in obj) {
entries.push([k, obj[k]]);
}
return entries;
}
// Determine the value of the tree selecting
// the one "winning" value to return from the
// reduce function
function reduceTree(tree, path) {
// If the node of the tree we're reducing has an
// explicit value then return that since it should
// take precedence over any children
if (tree.value) {
return tree.value;
}
// Otherwise reduce the children of the current node
// to get the "winning" node from
var toCombine = entries(tree.children).map(function (entry) {
return reduceTree(entry[1], path.concat([entry[0]]));
});
// Find the winning child by picking the one with
// the maximum value and return that
var ret = toCombine[0];
toCombine.forEach(function(child) {
if (child.data > ret.data)
ret = child;
});
return ret;
}
var ret = reduceTree(tree, []);
log({values: values, ret: ret})
return ret;
}
This works as long as descendants are reduced in the same invocation with any parent nodes that should take precedence, but when the parent ends up being dropped from the reduce (as in the example above) means the decedent is not replaced and can end up affecting the final calculation giving the wrong result.
I've tried gathering up the "contributing nodes" when reducing so that we retain the knowledge needed to know that a node is overwritten but that results in the "reduce function did not actually reduce the data" error.
Is this even possible with a reduce function or does it fundamentally break the constraints of a reduce function?

Increment variable on every call of method

I have this method :
void Session::onNewImage(cv::Mat& img, double elapsedTime){
static int count = 0;
add(img, dnnOutput[count++], curLati, curLongi, curAlti, curHeading, curRoll);
}
It's been called 1400 times. Each time the value of "count" is incremented. But when it comes at 1401 time, I want "count" to become 0 , and then again increment form there. I don't want "count" to be a global variable. How can i achieve this ?
P.S. I cannot hard code it as 1400. It can be different everytime. There is another method which decides how many times this method will be called, Depending on number of images given as input to that method.
This should do it:
void Session::onNewImage(cv::Mat& img, double elapsedTime){
static int count = 0;
if (count >= getYourCountLimitFromSomewhere())
count = 0;
add(img, dnnOutput[count++], curLati, curLongi, curAlti, curHeading, curRoll);
}
Note that as #Aconcagua has pointed out in the comments, whether the comparison of count with the threshold is via > or >= depends on the meaning of the getYourCountLimitFromSomewhere() return value.

How can I dynamically re-create a wxMenu (sub menu) with a variable number of items?

I want to create a list of COM ports in a sub menu that is updated every time the sub menu is viewed.
My plan:
Create a list of objects with data about each detected port, up to 32 object pointers. Example: comDetected *COMsFound[MAX_COM_DETECT]; (working)
Delete() old menu entries (working)
Create a new menu upon EVT_MENU_OPEN() with AppendRadioItem() (working)
Use EVT_MENU() to run the same function for each COM port selection
How do I determine in the event handling function (from wxCommandEvent?) which menu option caused the event? Without this information, I will need 32 separate functions.
Is there a more dynamic way to create the objects and events to avoid the arbitrary limit of 32 I have created?
Edit - This is what I have now for menu re-creation, which seems to be working:
Re-edit - not so good, as explained by bogdan
void FiltgenFrame::OnMenuOpen(wxMenuEvent& event)
{
//fill in COM port menu when opened
if(event.GetMenu() == COMSubMenu)
{
int i;
wxString comhelp;
//re-scan ports
comport->getPorts();
if(comport->COMdetectChanged == 1)
{
comport->currentCOMselection = 0; //when menu is regenerated, selection returns to 0
//get rid of old menu entries
for(i = 0; i < comport->oldnumCOMsFound; i++)
{
COMSubMenu->Delete(FILTGEN_COM1 + i);
COMSubMenu->Unbind(wxEVT_MENU, [i](wxCommandEvent&)
{
logMsg(DBG_MENUS, ACT_NORMAL, "menu COM select index: %d\n", i);
}, FILTGEN_COM1 + i);
}
//add new menu entries
for(i = 0; i < comport->numCOMsFound; i++)
{
comhelp.Printf("Use %s", comport->COMsFound[i]->name);
COMSubMenu->AppendRadioItem(FILTGEN_COM1 + i, comport->COMsFound[i]->name, comhelp);
COMSubMenu->Bind(wxEVT_MENU, [i](wxCommandEvent&)
{
comport->currentCOMselection = i;
logMsg(DBG_MENUS, ACT_NORMAL, "menu COM select index: %d\n", i);
}, FILTGEN_COM1 + i);
}
}
}
}
Edit - re-worked code 1-29-15. Broke apart OnMenuOpen and recreateCOMmenu due to factors unrelated to this question. Added COMselectionHandler because of advice.
void FiltgenFrame::COMselectionHandler(wxCommandEvent& event)
{
comport->currentCOMselection = event.GetId() - FILTGEN_COM1;
logMsg(DBG_MENUS, ACT_NORMAL, "COM menu select index: %d\n", comport->currentCOMselection);
}
void FiltgenFrame::recreateCOMmenu()
{
logMsg(DBG_MENUS, ACT_NORMAL, "FiltgenFrame::recreateCOMmenu():\n");
int i;
wxString comhelp;
//re-scan ports
comport->getPorts();
if(comport->COMdetectChanged == 1)
{
comport->currentCOMselection = 0; //when menu is regenerated, selection returns to 0
//get rid of old menu entries
for(i = 0; i < comport->oldnumCOMsFound; i++)
{
COMSubMenu->Delete(FILTGEN_COM1 + i);
COMSubMenu->Unbind(wxEVT_MENU, &FiltgenFrame::COMselectionHandler, this, FILTGEN_COM1 + i);
}
//add new menu entries
for(i = 0; i < comport->numCOMsFound; i++)
{
comhelp.Printf("Use %s", comport->COMsFound[i]->name);
COMSubMenu->AppendRadioItem(FILTGEN_COM1 + i, comport->COMsFound[i]->name, comhelp);
COMSubMenu->Bind(wxEVT_MENU, &FiltgenFrame::COMselectionHandler, this, FILTGEN_COM1 + i);
}
}
}
void FiltgenFrame::OnMenuOpen(wxMenuEvent& event)
{
//fill in COM port menu when opened
if(event.GetMenu() == COMSubMenu)
{
recreateCOMmenu();
}
}
Since dynamic seems to be the key word here, I would go for dynamic event handling (actually, I always go for dynamic event handling using Bind, it's so much nicer than the alternatives):
auto pm = new wxMenu(); //I suppose you're adding this to an existing menu.
std::wstring port_str = L"COM";
int id_base = 77; //However you want to set up the IDs of the menu entries.
for(int port_num = 1; port_num <= 32; ++port_num)
{
int id = id_base + port_num;
pm->AppendRadioItem(id, port_str + std::to_wstring(port_num));
pm->Bind(wxEVT_MENU, [port_num](wxCommandEvent&)
{
//Do something with the current port_num; for example:
wxMessageBox(std::to_wstring(port_num));
//You can also capture id if you prefer, of course.
}, id);
}
In the lambda expression, we capture the port number by value, so, for each iteration, the current port_num will be captured. This achieves exactly what you asked for: the same function (the operator() of the lambda's closure type) associated with each menu entry. The function knows the entry for which it was called because it has access to the captured port_num value, stored in the lambda's closure object - a small object, most likely the size of one int in this case.
To avoid a fixed limit on the number of objects, you can simply store them in a std::vector. If you want the vector to own the objects (have them destroyed automatically when the vector is destroyed), then you can store them directly in a std::vector<comDetected>. If something else owns the objects and takes care of destroying them separately, you could use std::vector<comDetected*>.
UPDATE: When writing my first solution, I didn't realize you'll want to Unbind and re-bind those event handlers; pretty obvious in hindsight, really, but... anyway, my mistake, sorry.
Here's the problem: as far as I can tell, there's no straightforward way to Unbind a lambda function object that was passed directly to Bind as I did in my example. Simply calling Unbind as you're doing in your updated code isn't going to work, because that Unbind will try to find an event handler that was installed by a corresponding call to Bind with the exact same arguments. That won't happen for the reasons explained in the next section (there's also an explanation for why it seems to work), but you might be more interested in solutions, so I'll start with those.
Solution 1 (the best one in your case): Forgo using lambdas; just use either a free function or a member function pointer. In this case, you'll need to get the menu entry ID from evt.GetId() and get the port index from it; something like this:
void handler_func(wxCommandEvent& evt)
{
int i = evt.GetId() - FILTGEN_COM1;
comport->currentCOMselection = i;
logMsg(DBG_MENUS, ACT_NORMAL, "menu COM select index: %d\n", i);
}
Then, your code would look like this:
void FiltgenFrame::OnMenuOpen(wxMenuEvent& event)
{
/* ... */
COMSubMenu->Unbind(wxEVT_MENU, handler_func, FILTGEN_COM1 + i);
/* ... */
COMSubMenu->Bind(wxEVT_MENU, handler_func, FILTGEN_COM1 + i);
/* ... */
}
The example above is using a free function. You can also use a member function - more info here.
Solution 2: In case you can rebuild that menu at some other time than EVT_MENU_OPEN(), you could go for destroying the whole wxMenu and rebuilding and inserting it into its parent menu in the right place. Destroying the old menu object will take care of all the dynamic event handlers bound to it, so you don't need to Unbind them. However, destroying the menu just before it's displayed doesn't sound like a good idea - I haven't tried it, but as far as I can tell it won't work, or behave in highly platform-dependent ways.
Here are the reasons for which Unbind won't work directly with lambdas:
The object generated by a lambda expression has a unique type. Even if you copy-paste the exact same lambda expression to another place in your code, that second lambda will generate a closure object of a type different from the one generated by the original lambda. Since Unbind checks the type of the functor argument against the types of the installed handlers, it will never find a match.
Even if we got around the problem above, there's another one: the function object passed to Unbind also needs to have the same address as the one passed to the corresponding Bind. The object generated when the lambda expression is passed directly to Bind is a temporary (it will typically be allocated on the stack), so making any assumptions about its address across function calls is just incorrect.
We can get around the two problems above (store the closure objects separately somewhere and so on), but I think any such solution is far too cumbersome to be worth considering - it will negate all the advantages of the lambda-based solution.
Here's why it seems to work in your code:
If Unbind doesn't find an event handler to remove, it just returns false; all existing handlers remain in there. Later on, Bind adds a new handler for the same event type and same entry ID at the front of the event handler list, so newer handlers are called first. Unless a handler calls evt.Skip() before returning, the event is considered handled after the handler returns and no other handlers are called.
Even though it sort of works as you expect, letting all those old unused handlers accumulate in the list every time the menu is rebuilt isn't a good idea, obviously.

Array keeps returning only the last element. [C/Arduino]

i've a problem with an array (called "Inputs" of type "GeneralInput") on Arduino,basically,no matter which element i try to have access to,the code always returns me the last element of that array.
Here's part of the code:
//...include statements
//other initializations
GeneralInput *Inputs[19];
void setup()
{
//...
//...
InitializeInputs();
}
void InitializeInputs()
{
//type 0 = pedal switch; 1 = volume pedal
//type 2 = potentiometer; 3= switch;
//pedal switches
Inputs[0] = &GeneralInput(0,0,true,false,NULL,10);
Inputs[1] = &GeneralInput(1,0,true,false,NULL,9);
Inputs[2] = &GeneralInput(2,0,true,false,NULL,6);
Inputs[3] = &GeneralInput(3,0,true,false,NULL,5);
//volume pedal
Inputs[4] = &GeneralInput(4,1,false,false,NULL,A2);
//potentiometer
Inputs[5] = &GeneralInput(5,2,false,true,mux2,5);
Inputs[6] = &GeneralInput(6,2,false,true,mux2,6);
Inputs[7] = &GeneralInput(7,2,false,true,mux2,7);
Inputs[8] = &GeneralInput(8,2,false,true,mux2,8);
Inputs[9] = &GeneralInput(9,2,false,true,mux2,9);
Inputs[10] = &GeneralInput(10,2,false,true,mux2,10);
Inputs[11] = &GeneralInput(11,2,false,true,mux2,11);
//switch
Inputs[12] = &GeneralInput(12,3,true,true,mux2,15);
Inputs[13] = &GeneralInput(13,3,true,true,mux2,14);
Inputs[14] = &GeneralInput(14,3,true,true,mux2,13);
Inputs[15] = &GeneralInput(15,3,true,true,mux2,12);
//joystick
Inputs[16] = &GeneralInput(16,3,true,true,mux1,2); //switch
Inputs[17] = &GeneralInput(17,2,false,true,mux1,1); //x axis
Inputs[18] = &GeneralInput(18,2,false,true,mux1,3); //y axis
}
void loop()
{
int length=0;
//cycle through different inputs
int startIndex=0,endIndex=0;
//temp arrays
byte toSendTmp[30];
for(int i=0;i<30;i++)
toSendTmp[i]=0;
//...
//..
int packetIndex=0;
for(int i=startIndex;i<endIndex;i++)
{
//if the input is updated,fill the array with the new data
/*
* When i try to have access to the i-element i always get
* the last one instead.
*/
if(Inputs[i]->Update())
{
toSendTmp[(packetIndex*3)] = Inputs[i]->GetID();
toSendTmp[(packetIndex*3)+1] = Inputs[i]->GetType();
toSendTmp[(packetIndex*3)+2] = Inputs[i]->GetValue();
packetIndex++;
}
}
//....
//...
}
And if needed here's the GeneralInput.h and GeneralInput.cpp code.
NOTE: I can't tell if the array is always returning the last item or if every slot of the array is filled with a pointer to the same object (the last created).
Any idea on what i'm doing wrong?
Thanks in advance.
Your &GeneralInput are incorrect, in fact you create temporary objects and store their adresses in an array, but as soon as your GeneralInput object get destroy (same line as creation), a new object takes place at the same address:
// Create GeneralInput at address #
Inputs[0] = &GeneralInput(0,0,true,false,NULL,10);
// End of your temporary object, the `GeneralInput` object is destroyed but you still
// points to its address...
/* etc. */
You're getting the last value because the compiler always create the GeneralInput at the same address, so all Inputs[] point to the same address.
You need to dynamically create your GeneralInput:
Inputs[0] = new GeneralInput(0,0,true,false,NULL,10);
Every slot in the array has a pointer to the same memory location which is the occupied by the last element you create. By doing &GeneralInput(...) you are creating a GeneralInput object on the stack and retrieving its stack address. But since the GeneralInput object itself is never assigned to a variable, the memory it occupies is immediately available for reuse. This means that every GeneralInput object is created at the same address on the stack. The solution, however, isn't to change your code to something like
GeneralInput genInput = GeneralInput(...);
Inputs[...] = &genInput;
Code like that will still be filling your array with pointers to stack addresses. Those pointers will immediately become invalid when the function returns. You should be filling your array with something like
Inputs[...] = (GeneralInput*)malloc(sizeof(GeneralInput));
*Inputs[...] = GeneralInput(...);
Using this method make sure that if your Inputs array ever reaches a point where you don't use it anymore loop over it freeing every element.
Edit: Arduino using C, so doesn't have new. Use malloc and free instead.
As others have said, the problem is with the address of the temporary variables. You can get around the "new" problem by having default parameters.
class GeneralInput
{
public:
GeneralInput(int a = 0, int b = 0, bool c = true, bool d = true, int* e = NULL, int f = 0);
...
};
Then declare your array - this takes GeneralInput with the default parameters
GeneralInput inputs[20];
Then in Initialize - then you won't have the new problem or the problem of temporaries disappearing at the end of the routine.
void InitializeInputs()
{
inputs[0] = GeneralInput(0,0,true,false,NULL,10);
...
}
I don't know what the NULL points to but you might want to put in a copy operator for this if it is anything else other than copying the value. Not very efficient because it calls the constructor twice but that only happens at initialization.