Basically, I'm trying to make the smart contract be able to take exactly 0.05 eth ONLY when the cooldown timer is set to 0. The Dapp I'm creating is a first come first serve eth advertising service, where the user can upload an image or gif within the dapp, then pay 0.05 eth to trigger the advertisement to run for x amount of time. When the time runs out, the next user can purchase their ad slot.
The timer seems to work, but I cant get the timer to start upon payment.
I would really appreciate the help, here is what I have so far:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract AdEth {
//This sets up the name of the ad and if it is running, set to false by default
//Variables for start, end, cooldown (cool down can be changed here)
address payable public owner;
uint _start;
uint _end;
uint cooldownTime = 1 minutes;
constructor() {
owner = payable(msg.sender);
}
modifier timerOver {
require(block.timestamp <= _end, "The Cooldown is over");
_;
}
modifier onlyWhileOpen {
require(block.timestamp >= _start && block.timestamp <= _end);
_;
}
function start() public {
_start = block.timestamp;
end(cooldownTime);
}
function end(uint totalTime) public {
_end = totalTime + _start;
}
function getTimeLeft() public view returns(uint) {
return _end - block.timestamp;
}
receive() external payable {
}
function receiveAdPayment() payable public returns (bool) {
require(msg.value == 0.05 ether, "Not enough ether. 0.05 Needed.");
require(cooldownTime == 0, "There is currently an add running. Please wait until the cooldown is finished.");
msg.sender.transfer(0.05 ether);
start();
return true;
}
function withdrawAll(uint _amount) external {
require(msg.sender == owner, "Caller is not the owner.");
payable(msg.sender).transfer(_amount);
}
function getBalance() external view returns (uint) {
return address(this).balance;
}
}
------------EDITS 5.11.21--------------
I have swapped out all of the timestamps for block.number and everything is working as intended. However, I want the smart contract to automatically call the setRunning() function when the cooldownTime expires. Is this possible? or is this the best its going to get?
Appreciate any and all help!
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract AdEth {
//This sets up the name of the ad and if it is running, set to false by default
//Variables for start, end, cooldown (cool down can be changed here)
address payable public owner;
uint _start;
uint _end;
//The number is in BLOCKS (~15 sec each, rinkeby approx ~1 min)
uint cooldownTime = 4;
bool running;
constructor() {
owner = payable(msg.sender);
}
function start() internal {
_start = block.number;
_end = block.number + cooldownTime;
running = true;
}
function getTimeLeft() public view returns(uint) {
return _end - block.number;
}
//This allows the owner to set "running" to false only if the required amount of cooldown blocks is reached.
function setRunning() public {
require(msg.sender == owner, "You are not the owner.");
require(block.number > _end, "Wait for the cooldown to expire before you can reset running to false.");
running = false;
}
function isRunning() public view returns (bool) {
return running;
}
function receiveAdPayment() payable public {
require(msg.value >= 0.05 ether, "At Least 0.05 ETH Needed.");
require(block.number > _end, "There is currently an ad running. Please wait until the cooldown is finished.");
require(running != true, "The ad time may have run out, but has not been reset by Admin.");
start();
}
function withdraw(uint _amount) external {
require(msg.sender == owner, "Caller is not the owner.");
payable(msg.sender).transfer(_amount);
}
function getBalance() external view returns (uint) {
return address(this).balance;
}
}
----EDITS 5.18.22------
Ok here is the final product. Got pushed in a bunch of directions and chose the below code. It is working well in remix.
Thanks everyone!
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import '#openzeppelin/contracts/access/Ownable.sol';
contract AdEth is Ownable {
//This sets up the name of the ad and if it is running, set to false by default
//Variables for start, end, cooldown (cool down can be changed here)
uint _start;
uint _end;
uint cooldownTime = 3 minutes;
uint runNumber = 0;
function start() internal {
_start = block.timestamp;
_end = block.timestamp + cooldownTime;
runNumber++;
}
function getTimeLeft() public view returns(uint) {
return _end - block.timestamp;
}
function adRunNumber() public view returns (uint) {
return runNumber;
}
function receiveAdPayment() payable public {
require(msg.value >= 0.05 ether, "At Least 0.05 ETH Needed.");
require(block.timestamp > _end, "There is currently an ad running. Please wait until the cooldown is finished.");
start();
}
function withdraw(uint _amount) external onlyOwner {
payable(msg.sender).transfer(_amount);
}
function getBalance() external view returns (uint) {
return address(this).balance;
}
}
First thing: NEVER use block.timestamp. It's not validated and can be abused. Use the block number as a form of timestamp instead.
Second thing: start() should be internal. Currently, anyone can call this, and this does not seem to be intentional behavior.
Finally, your issue: It appears you have two payable methods. The first one is the one that will be called. Remove the receive() function.
Related
I want to have a network of clients and servers in this network. To connect to the edge servers, the clients first check the validity of the edge server and then connect to it, and the client also connects to the said edge. . The client calculates the credibility of this edge server. In this code, I want to calculate the reputation of the edge server, so I have mapped the address of the edge server and the client to the reputation and used an identifier to search. I get an error when I run the ComputeReputation function.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "https://github.com/PaulRBerg/prb-math/blob/v1.0.3/contracts/PRBMathSD59x18.sol";
contract Reputationcalculation{
using PRBMathSD59x18 for int256;
struct edgeserver{
bool exists;
uint placed_bids;
uint reputation;
uint deposit;
}
mapping (address => edgeserver) public edgeserver_suppliers;
struct mobileuser{
bool exists;
uint deposit;
//credbility
bool auction_open;
}
mapping (address => mobileuser) public mobileusers;
mapping(address => mapping(address =>mapping (uint=>uint))) public reputation;
mapping(uint => edgeserver) public listedgeservers;
mapping(address => mapping(address => uint)) public reputationid;
//mapping (uint => address) public mobile_user;
//mapping (uint => address) public edge_server;
address payable private owner;
address[] public mobile_user;
address[] public edge_server;
uint SIC;
uint n;
uint u;
uint s;
address client;
address server;
uint reputationSum ;
//uint numRatings;
uint id=0;
uint reputationlength;
uint reputationAverage;
modifier onlyOwner{
require(msg.sender == owner,"Sender not authorized.");
_;
}
modifier onlyClient{
require(mobileusers[msg.sender].exists,"Sender not authorized.");
_;
}
modifier onlySupplier{
require(edgeserver_suppliers[msg.sender].exists,"Sender not authorized.");
_;
}
event edgeserverRegistered(address supplierAddress);
event mobileuserRegistered(address clientAddress);
constructor () public{
owner =payable( msg.sender);
n=0;
SIC=0;
u=0;
s=0;
reputationSum = 0;
//numRatings = 0;
reputationlength=0;
reputationAverage=0;
// client=msg.sender;
}
function addmobileuser() payable public{
require(!mobileusers[msg.sender].exists,"mobileuser already registered");
require(!edgeserver_suppliers[msg.sender].exists,"Address registerd as a edgeserver");
mobileusers[msg.sender]=(mobileuser(true,msg.value,false));
client=msg.sender;
u++;
emit mobileuserRegistered(msg.sender);
}
function addedgeserver(address supplier) onlyOwner public{
require(!mobileusers[supplier].exists,"Address registerd as a mobile user");
edgeserver_suppliers[supplier]=(edgeserver(true,0,0,0));
server=msg.sender;
s++;
emit edgeserverRegistered(supplier);
}
function SetReputation(address mobile, address edge, uint rating) public {
mobile_user.push(mobile);
edge_server.push(edge);
reputation[mobile][edge][id]= rating;
id++;
reputationlength=id;
}
function ComputeReputation(address user )public {
uint numRatings = 0;
address mobile;
address edge;
for(id=0;id<=reputationlength;id++)
{
mobile=mobile_user[id];
edge=edge_server[id];
if(user==mobile){
reputationSum += reputation[mobile][edge][id];
numRatings++;
}
}
}
function getReputation( ) public returns(uint )
{
reputationSum;
}
}
Please help. Thank you
Actually, my problem is searching in the map. I want to calculate the total reputation given to each edge server by a specific client. Also, later, I plan to calculate the total reputation given by each client to a specific server. Please help me.
I am implementing Circuit breaker using Hystrix in my Spring boot application, my code is something like below:
#service
public class MyServiceHandler {
#HystrixCommand(fallbackMethod="fallback")
public String callService() {
// if(remote service is not reachable
// throw ServiceException
}
public String fallback() {
// return default response
}
}
// In application.properties, I have below properties defined:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000
hystrix.command.default.circuitBreaker.requestVolumeThreshold=3
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=30000
hystrix.threadpool.default.coreSize=4
hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds=200000
I see that the fallback() is getting called with each failure of callService(). However, the circuit is not opening after 3 failures. After 3 failures, I was expecting that it will directly call fallback() and skip callService(). But this is not happening. Can someone advise what I am doing wrong here?
Thanks,
B Jagan
Edited on 26th July to add more details below:
Below is the actual code. I played a bit further with this. I see that the Circuit opens as expected on repeated failured when I call the remote service directly in the RegistrationHystrix.registerSeller() method. But, when I wrap the remote service call within Spring retry template, it keeps going into fallback method, but circuit never opens.
#Service
public class RegistrationHystrix {
Logger logger = LoggerFactory.getLogger(RegistrationHystrix.class);
private RestTemplate restTemplate;
private RetryTemplate retryTemplate;
public RegistrationHystrix(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(1000l);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(3);
retryTemplate.setRetryPolicy(retryPolicy);
}
#HystrixCommand(fallbackMethod = "fallbackForRegisterSeller", commandKey = "ordermanagement")
public String registerSeller(SellerDto sellerDto) throws Exception {
String response = retryTemplate.execute(new RetryCallback<String, Exception>() {
#Override
public String doWithRetry(RetryContext context) {
logger.info(String.format("Retry count %d", context.getRetryCount()));
return restTemplate.postForObject("/addSeller", sellerDto, String.class);
}
});
return response;
}
public List<SellerDto> getSellersList() {
return restTemplate.getForObject("/sellersList", List.class);
}
public String fallbackForRegisterSeller(SellerDto sellerDto, Throwable t) {
logger.error("Inside fall back, cause - {}", t.toString());
return "Inside fallback method. Some error occured while calling service for seller registration";
}
}
Below is the service class which in turn calls the above Hystrix wrapped service. This class in turn is invoked by a controller.
#Service
public class RegistrationServiceImpl implements RegistrationService {
Logger logger = LoggerFactory.getLogger(RegistrationServiceImpl.class);
private RegistrationHystrix registrationHystrix;
public RegistrationServiceImpl(RegistrationHystrix registrationHystrix) {
this.registrationHystrix = registrationHystrix;
}
#Override
public String registerSeller(SellerDto sellerDto) throws Exception {
long start = System.currentTimeMillis();
String registerSeller = registrationHystrix.registerSeller(sellerDto);
logger.info("add seller call returned in - {}", System.currentTimeMillis() - start);
return registerSeller;
}
So, I am trying to understand why the Circuit breaker is not working as expected when using it along with Spring RetryTemplate.
You should be using metrics.healthSnapshot.intervalInMilliseconds while testing. I guess you are executing all 3 request within default 500 ms and hence the circuit isn't getting open. You can either decrease this interval or you may put a sleep between the 3 requests.
Following methods are used to start and stop location tracking using my App to poll the location continuously almost every minute. I would like to capture the location only when there is a change in coordinates. I'm wondering there is any method that would do comparison and retrieve location when there is a change.
I have tried to manually compare the coordinates which is making the requests slow down. Please advise.
public void stopTracking() {
if (time != null) {
time.cancel();
}
time = null;
LocationManager.getLocationManager().setLocationListener(null);
}
public void startTracking() {
if (time != null) {
stopTracking();
}
if (Preferences.get("LocationTracking", true)) {
long delay = Server.instance.getLoctionPollingIntervalMillis();
LocationManager.getLocationManager().setLocationListener(this,
new LocationRequest(LocationRequest.PRIORITY_LOW_ACCUARCY, delay));
time = new Timer();
time.schedule(new TimerTask() {
#Override
public void run() {
if (lastLocation != null) {
double lat = (double) lastLocation.getLatitude();
double lot = (double) lastLocation.getLongitude();
Server.instance.updateLocationInServer(lat, lot, System.currentTimeMillis(), true);
}
}
}, 30000, delay);
}
}
Remove the timer code and write the server update in the LocationRequest class which is invoked by the listener. I'd also suggest adding an update threshold as some implementations can update you on a very high frequency and on movement that's very fine.
I am building a form application and press on a button which is looping in while loop till it founds some results. But this looping is requesting some server. I would like to throtle these requests to max 5 requests in 1 minute. So there needs to come some logic which is sleeping till the new minutes started. Please can someone help me?
Here is my code:
public int RPMCounter { get; set; }
private async void SearchCheapestAuction()
{
bool foundItem = false;
textBoxLogging.Clear();
textBoxLogging.Text += System.Environment.NewLine + "start";
// 1 stay loooping till you found this item for the buynowprice
while (!foundItem)
{
// 2 check if this is request number 5 in one minute
if (RPMCounter <= 5)
{
// 3 increase counter
RPMCounter++;
// 4 set searchparameters
var searchParametersPlayers = new PlayerSearchParameters
{
MaxBid = (uint)Convert.ToInt16(textBoxMaxStartPrice.Text),
MinBid = (uint)Convert.ToInt16(textBoxMinStartPrice.Text),
MaxBuy = (uint)Convert.ToInt16(textBoxMaxBuyNow.Text),
MinBuy = (uint)Convert.ToInt16(textBoxMinBuyNow.Text)
};
// 5 run search query
var searchResponse = await client.SearchAsync(searchParametersPlayers);
// 8 check if the search found any results
if (searchResponse.AuctionInfo.Count > 0)
{
// 9 buy this player for the buy now price
var auctionResponse = await client.PlaceBidAsync(searchResponse.AuctionInfo.First(), searchResponse.AuctionInfo.First().BuyNowPrice);
// 10 stop searching/buying, I found my item for the right price
return;
}
}
else
{
// 11 I access the 5 rpm, sleep till the next minutes begin and go search again?
return;
}
}
textBoxLogging.Text += System.Environment.NewLine + "finished";
}
}
I wouldn't handle it this way.
The way you designed this will have the following effect: You will make the server request 5 times in a row in arbitrarily short intervals, then you will wait for a minute and call again 5 times in a row in arbitrarily short intervals.
If that's what you intend to do, can you explain exactly why you need it that way ?
Limiting the number of calls to 5 per minute could be done easily by simply having a System.Timers.Timer with an interval of 12 seconds and checking if your request is done.
If it is and you haven't found the item, you can make a new one, and if it isn't, you can wait for the next time that your timer is elapsed.
It could look something like this:
private Timer _requestTimer;
private readonly object _requestLock = new object();
private bool _requestSuccessful;
private void StartRequestTimer()
{
_requestTimer = new Timer(12 * 1000) { AutoReset = true };
_requestTimer.Elapsed += requestTimer_Elapsed;
_requestTimer.Start();
}
void requestTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (_requestLock)
{
if (_requestSuccessful)
{
_requestTimer.Stop();
}
else
{
TryNewRequest();
}
}
}
private void TryNewRequest()
{
lock (_requestLock)
{
//try a new asynchronous request here and set _requestSuccessful to true if successful
}
}
In your main function, you would first call TryNewRequest() then you would call StartRequestTimer(). Note that the request has to be asynchronous for this to work properly.
I'm having a big problem using WP7 isolated storage and applicationsettings.
I have been using code from Adam Nathan's 101 Windows Phone 7 apps volume 1 as a basis.
I have a settings page where values can be altered and whilst the application is still running these remain active and it all works perfectly. However, as soon as the app exits on my developer phone these are lost and the app restarts with the default settings.
I have no idea why these values are not persisting. Any help would be much appreciated.
Here is the code i've got, its from adam nathan's new book. I sent him a message on twitter and he said its to do with a data type that isn't serializable. I looked into this but i'm only using double and bool values.
public class Setting<T>
{
string name;
T value;
T defaultValue;
bool hasValue;
public Setting(string name, T defaultValue)
{
this.name = name;
this.defaultValue = defaultValue;
}
public T Value
{
get
{
//checked for cached value
if (!this.hasValue)
{
//try to get value from isolated storage
if (IsolatedStorageSettings.ApplicationSettings.TryGetValue(this.name, out this.value))
{
//not set yet
this.value = this.defaultValue;
IsolatedStorageSettings.ApplicationSettings[this.name] = this.value;
}
this.hasValue = true;
}
return this.value;
}
set
{
//save value to isolated storage
IsolatedStorageSettings.ApplicationSettings[this.name] = value;
this.value = value;
this.hasValue = true;
}
}
public T DefaultValue
{
get { return this.defaultValue; }
}
//clear cached value;
public void ForceRefresh()
{
this.hasValue = false;
}
}
Further development:
I receive this error on exiting the application:
A first chance exception of type 'System.IO.IsolatedStorage.IsolatedStorageException' occurred in mscorlib.dll
ERROR FOUND: I'm an idiot and left out one exclamation mark! from the trygetvalue part.
Could you please post your storage code so we could see exactly what's going on? In absense of that code, here's the code I use to save setting to local storage:
IsolatedStorageSettings isoStoreSettings = IsolatedStorageSettings.ApplicationSettings;
if (isoStoreSettings.Contains(key))
{
isoStoreSettings[key] = value;
}
else
{
isoStoreSettings.Add(key, value);
}
isoStoreSettings.Save();
My guess is that you're missing that last line that commits the changes to isolated storage settings to the materialized isolated store instead of just leaving them in memory. If that's not the case, please edit your post with the code so that we can help.