"Out of Gas" when calling function twice quickly, but not when calls are spaced out? - solidity

I have a smart contract, and one of the functions (queue) is meant to allow users to find "matches" with other users of the smart contract. The logic is that if you call queue and there is nobody waiting, you are now the queued user / wallet address. If you call queue and there is already a queued user, you clear them from the queue and set up the match.
This works fine if the first queue call is a few seconds before the second one, but if both users call queue at the same time, the second one always reverts with an Out of Gas error. Increasing the amount of gas does not solve the issue.
I would appreciate any ideas!
The code fails in the if block. If I remove most of the logic, it succeeds, but I can't figure out any rhyme or reason as to why.
if (awaitingMatch != address(0)) {
userMap[awaitingMatch].opponent = msg.sender;
userMap[awaitingMatch].matchedBlock = block.number;
userMap[awaitingMatch].matchWins = 0;
userMap[awaitingMatch].playAmount = msg.value;
userMap[awaitingMatch].winsNeeded = winsToWin;
userMap[msg.sender].opponent = awaitingMatch;
userMap[msg.sender].matchedBlock = block.number;
userMap[msg.sender].matchWins = 0;
userMap[msg.sender].winsNeeded = winsToWin;
awaitingMatch = address(0);
emit Match(msg.sender);
emit Match(userMap[msg.sender].opponent);
// add this guy to the list awaiting a match, and set his desposit flag true
} else {
awaitingMatch = msg.sender;
}

I think I have figured this out. The issue is that MetaMask tries to estimate the amount of gas that will be used for each transaction. MetaMask is quite good at this, and analyzes the state of the contract before estimating the gas. The if section (run by the second caller) does a lot more work than the else section (run by the first caller). If I make both calls at the same time, they both estimate that they'll run the lighter else section, but one of them will wind up running the first, more expensive if section.
I think my best bet here is to tweak the amount of gas being supplied on any call to a function like this that could do quite different amounts of work depending on the moment the function is called.

Related

Why does this solidity function run into gas errors?

I'm trying to figure out some strange behavior. The function below takes in an array like [1,2,3,4,5], loops through it, and looks at another contract to verify ownership. I wrote it like this (taking in a controlled / limited array) to limit the amount of looping required (to avoid gas issues). The weird part (well, to me) is that I can run this a few times and it works great, mapping the unmapped values. It will always process as expected until I run about 50 items through it. After that, the next time it will gas out even if the array includes only one value. So, I'm wondering what's going on here...
function claimFreeNFTs (uint[] memory _IDlist) external payable noReentrant {
IERC721 OGcontract = IERC721(ERC721_contract);
uint numClaims = 0;
for (uint i = 0; i < _IDlist.length; i++) {
uint thisID = _IDlist[i];
require(OGcontract.ownerOf(thisID)==msg.sender, 'Must own token.' );
if ( !claimedIDList(thisID) ) { // checks mapping here...
claimIDset(thisID); // maps unmapped values here;
numClaims++;
}
}
if ( numClaims > 0 ) {
_safeMint(msg.sender, numClaims);
emit Mint(msg.sender, totalSupply());
}
}
Any thoughts / directions appreciated. :-)
Well, there was a bit more to the function, actually. I'd edited out some of what I thought was extraneous, but it turned out my error was in the extra stuff. The above does actually work. (Sorry.) After doing the mint, I was also reducing the supply of a reserve wallet on the contract -- one that held (suprise!) 50 NFTs. So, after this function processed 50, it was making that wallet hold negative NFTs, which screwed things up. Long story, but on Remix, I'd forgotten to set values in the constructor in the proper order, which is how I screwed it up in the first place. Anyway, solved.

Why should I use & in this syntax? Problem with SPI register

I'm writing a program for SPI communication betweend LPC2109/2 and MCP4921. This is an assignment
on studies. My tutor ask me a question why "&" is necessary in this line? In this line we wait for the end of SPI transmission. Which answer should be right?
#define SPI_SPIF_bm (1<<7)
...
while((S0SPSR & SPI_SPIF_bm) == 0){}
We use "&" as logic AND, for instance: (0000 & 1000) gives us 0000 instead of (0000 | 1000) gives us 1000.
Can I use only this line of code: while((S0SPSR) == 0){}? In my opinion - no. We need to compare value in register S0SPSR with bit SPIF SPI_SPIF_bm.
Is there maybe different solution?
Attachment
User Manual for LPC2129/01: https://www.nxp.com/docs/en/user-guide/UM10114.pdf
The SPI peripheral of LPC2109/2 sets different bits of S0SPSR depending on the actual event that happens which may depend on external circumstances. For example if there's a write collision on the SPI line it sets the WCOL bit instead of SPIF.
If you use while((S0SPSR) == 0){} it will wait until either a successful transaction or an error happens because it will exit the loop if any of the bits of S0SPSR is set.
while((S0SPSR & SPI_SPIF_bm) == 0){} only checks if the transaction has completed successfully. It is a good practice to check the error bits too because in case of an error you would stuck in this loop forever as SPIF is never goint to be set.
For a robust solution I would go with something like this:
while(S0SPSR == 0) {}
if (S0SPSR & SPI_SPIF_bm) { /* SPI_SPIF_bm remains set until data register has not been accessed */
/* Success, read the data register, return data, etc. */
} else {
/* Handle error */
}
If you are interested in the particular type of the error you need to store S0SPSR in a variable in each cycle as those bits are cleared on reading S0SPSR. Also you should to add a counter or a more sophisticated timeout solution to the loop to exit if none of the flags are sets in a reasonable period.
You might think these errors would never happen because you have a simple circuit but they do happen in real life and it's worth doing proper error handling.

Akka.net scheduler sends just first value and doesn't update it, How fix it

I can't find the answer to an interesting moment.
in akka.net I have the scheduler. It will work in actor which are sort out a number.
here a simple implementation
_statusScheduler = Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(
TimeSpan.FromSeconds(_shedulerInterval),
TimeSpan.FromSeconds(_shedulerInterval),
_reporterActor,
new ProgressReport(requestId, _testedQuantity),
Self);
where
_shedulerInterval - 5-second interval,
_testedQuantity - quantity of tested number all time updated.
and after 5 seconds it is sent 0; always, not a changed number. And here is a question: is it possible to send updated quantity?
I can't send the message to the updating quantity from Recieve<> methods, because my actor is handled the counting message and it is counted the quantity all the time and updated it(when it finished it will receive next message). But all five seconds I should generate a report by a scheduler. Is it possible to fix it?
I think now I need to send all logic because it works fine, and the stone of my problem is scheduler behavior.
The issue you have here is that the message you pass into the scheduler, new ProgressReport(requestId, _testedQuantity), is what is going to be sent each time. Since you're passing in those integer values by value, the object is going to have the original values for those fields at the time you created the message and therefore the message will never update.
If you want to be able to change the content that is sent in the recurring scheduler, do this instead:
var self = Self; // need a closure here, since ActorContext won't be available
_statusScheduler = Context.System.Scheduler.Advanced.ScheduleRepeatedlyCancelable(interval, interval, () => {
_reporterActor.Tell(new ProgressReport(requestId, _testedQuantity), self);
});
This usage of the scheduler will generate a new message each time when it invokes the lambda function and thus you'll be able to include the updated integer values inside your object.

Embedded System - Polling

I have about 6 sensors (GPS, IMU, etc.) that I need to constantly collect data from. For my purposes, I need a reading from each (within a small time frame) to have a complete data packet. Right now I am using interrupts, but this results in more data from certain sensors than others, and, as mentioned, I need to have the data matched up.
Would it be better to move to a polling-based system in which I could poll each sensor in a set order? This way I could have data from each sensor every 'cycle'.
I am, however, worried about the speed of polling because this system needs to operate close to real time.
Polling combined with a "master timer interrupt" could be your friend here. Let's say that your "slowest" sensor can provide data on 20ms intervals, and that the others can be read faster. That's 50 updates per second. If that's close enough to real-time (probably is close for an IMU), perhaps you proceed like this:
Set up a 20ms timer.
When the timer goes off, set a flag inside an interrupt service routine:
volatile uint8_t timerFlag = 0;
ISR(TIMER_ISR_whatever)
{
timerFlag = 1; // nothing but a semaphore for later...
}
Then, in your main loop act when timerFlag says it's time:
while(1)
{
if(timerFlag == 1)
{
<read first device>
<read second device>
<you get the idea ;) >
timerflag = 0;
}
}
In this way you can read each device and keep their readings synched up. This is a typical way to solve this problem in the embedded space. Now, if you need data faster than 20ms, then you shorten the timer, etc. The big question, as it always is in situations like this, is "how fast can you poll" vs. "how fast do you need to poll." Only experimentation and knowing the characteristics and timing of your various devices can tell you that. But what I propose is a general solution when all the timings "fit."
EDIT, A DIFFERENT APPROACH
A more interrupt-based example:
volatile uint8_t device1Read = 0;
volatile uint8_t device2Read = 0;
etc...
ISR(device 1)
{
<read device>
device1Read = 1;
}
ISR(device 2)
{
<read device>
device2Read = 1;
}
etc...
// main loop
while(1)
{
if(device1Read == 1 && device2Read == 1 && etc...)
{
//< do something with your "packet" of data>
device1Read = 0;
device2Read = 0;
etc...
}
}
In this example, all your devices can be interrupt-driven but the main-loop processing is still governed, paced, by the cadence of the slowest interrupt. The latest complete reading from each device, regardless of speed or latency, can be used. Is this pattern closer to what you had in mind?
Polling is a pretty good and easy to implement idea in case your sensors can provide data practically instantly (in comparison to your desired output frequency). It does get into a nightmare when you have data sources that need a significant (or even variable) time to provide a reading or require an asynchronous "initiate/collect" cycle. You'd have to sort your polling cycles to accommodate the "slowest" data source.
What might be a solution in case you know the average "data conversion rate" of each of your sources, is to set up a number of timers (per data source) that trigger at poll time - data conversion rate and kick in the measurement from those timer ISRs. Then have one last timer that triggers at poll timer + some safety margin that collects all the conversion results.
On the other hand, your apparent problem of "having too many measurements" from the "fast" data sources wouldn't bother me too much as long as you don't have anything reasonable to do with that wasted CPU/sensor load.
A last and easier approach, in case you have some cycles to waste, is: Simply sort the data sources from "slowest" to "fastest" and initiate a measurement in that order, then wait for results in the same order and poll.

Keeping time using timer interrupts an embedded microcontroller

This question is about programming small microcontrollers without an OS. In particular, I'm interested in PICs at the moment, but the question is general.
I've seen several times the following pattern for keeping time:
Timer interrupt code (say the timer fires every second):
...
if (sec_counter > 0)
sec_counter--;
...
Mainline code (non-interrupt):
sec_counter = 500; // 500 seconds
while (sec_counter)
{
// .. do stuff
}
The mainline code may repeat, set the counter to various values (not just seconds) and so on.
It seems to me there's a race condition here when the assignment to sec_counter in the mainline code isn't atomic. For example, in PIC18 the assignment is translated to 4 ASM statements (loading each byte at the time and selecting the right byte from the memory bank before that). If the interrupt code comes in the middle of this, the final value may be corrupted.
Curiously, if the value assigned is less than 256, the assignment is atomic, so there's no problem.
Am I right about this problem?
What patterns do you use to implement such behavior correctly? I see several options:
Disable interrupts before each assignment to sec_counter and enable after - this isn't pretty
Don't use an interrupt, but a separate timer which is started and then polled. This is clean, but uses up a whole timer (in the previous case the 1-sec firing timer can be used for other purposes as well).
Any other ideas?
The PIC architecture is as atomic as it gets. It ensures that all read-modify-write operations to a memory file are 'atomic'. Although it takes 4-clocks to perform the entire read-modify-write, all 4-clocks are consumed in a single instruction and the next instruction uses the next 4-clock cycle. It is the way that the pipeline works. In 8-clocks, two instructions are in the pipeline.
If the value is larger than 8-bit, it becomes an issue as the PIC is an 8-bit machine and larger operands are handled in multiple instructions. That will introduce atomic issues.
You definitely need to disable the interrupt before setting the counter. Ugly as it may be, it is necessary. It is a good practice to ALWAYS disable the interrupt before configuring hardware registers or software variables affecting the ISR method. If you are writing in C, you should consider all operations as non-atomic. If you find that you have to look at the generated assembly too many times, then it may be better to abandon C and program in assembly. In my experience, this is rarely the case.
Regarding the issue discussed, this is what I suggest:
ISR:
if (countDownFlag)
{
sec_counter--;
}
and setting the counter:
// make sure the countdown isn't running
sec_counter = 500;
countDownFlag = true;
...
// Countdown finished
countDownFlag = false;
You need an extra variable and is better to wrap everything in a function:
void startCountDown(int startValue)
{
sec_counter = 500;
countDownFlag = true;
}
This way you abstract the starting method (and hide ugliness if needed). For example you can easily change it to start a hardware timer without affecting the callers of the method.
Write the value then check that it is the value required would seem to be the simplest alternative.
do {
sec_counter = value;
} while (sec_counter != value);
BTW you should make the variable volatile if using C.
If you need to read the value then you can read it twice.
do {
value = sec_counter;
} while (value != sec_counter);
Because accesses to the sec_counter variable are not atomic, there's really no way to avoid disabling interrupts before accessing this variable in your mainline code and restoring interrupt state after the access if you want deterministic behavior. This would probably be a better choice than dedicating a HW timer for this task (unless you have a surplus of timers, in which case you might as well use one).
If you download Microchip's free TCP/IP Stack there are routines in there that use a timer overflow to keep track of elapsed time. Specifically "tick.c" and "tick.h". Just copy those files over to your project.
Inside those files you can see how they do it.
It's not so curious about the less than 256 moves being atomic - moving an 8 bit value is one opcode so that's as atomic as you get.
The best solution on such a microcontroller as the PIC is to disable interrupts before you change the timer value. You can even check the value of the interrupt flag when you change the variable in the main loop and handle it if you want. Make it a function that changes the value of the variable and you could even call it from the ISR as well.
Well, what does the comparison assembly code look like?
Taken to account that it counts downwards, and that it's just a zero compare, it should be safe if it first checks the MSB, then the LSB. There could be corruption, but it doesn't really matter if it comes in the middle between 0x100 and 0xff and the corrupted compare value is 0x1ff.
The way you are using your timer now, it won't count whole seconds anyway, because you might change it in the middle of a cycle.
So, if you don't care about it. The best way, in my opinion, would be to read the value, and then just compare the difference. It takes a couple of OPs more, but has no multi-threading problems.(Since the timer has priority)
If you are more strict about the time value, I would automatically disable the timer once it counts down to 0, and clear the internal counter of the timer and activate once you need it.
Move the code portion that would be on the main() to a proper function, and have it conditionally called by the ISR.
Also, to avoid any sort of delaying or missing ticks, choose this timer ISR to be a high-prio interrupt (the PIC18 has two levels).
One approach is to have an interrupt keep a byte variable, and have something else which gets called at least once every 256 times the counter is hit; do something like:
// ub==unsigned char; ui==unsigned int; ul==unsigned long
ub now_ctr; // This one is hit by the interrupt
ub prev_ctr;
ul big_ctr;
void poll_counter(void)
{
ub delta_ctr;
delta_ctr = (ub)(now_ctr-prev_ctr);
big_ctr += delta_ctr;
prev_ctr += delta_ctr;
}
A slight variation, if you don't mind forcing the interrupt's counter to stay in sync with the LSB of your big counter:
ul big_ctr;
void poll_counter(void)
{
big_ctr += (ub)(now_ctr - big_ctr);
}
No one addressed the issue of reading multibyte hardware registers (for example a timer.
The timer could roll over and increment its second byte while you're reading it.
Say it's 0x0001ffff and you read it. You might get 0x0010ffff, or 0x00010000.
The 16 bit peripheral register is volatile to your code.
For any volatile "variables", I use the double read technique.
do {
t = timer;
} while (t != timer);