I created a function where one of my contracts instantiates another and it suddenly pushed the whole contract over the size limit. Here's the function:
function createContract(E.BKLiteMeta memory meta)
public
payable
returns(address)
{
require(meta.publisherAddress == msg.sender, "only pub");
return(address(new BKopyLite(meta)));
}
Hardhat size-contracts reports the size of the contract 24.02. When I change the function to:
function createContract(E.BKLiteMeta memory meta)
public
payable
returns(address)
{
require(meta.publisherAddress == msg.sender, "only pub");
return(address(0);
}
`size-contracts' reports a size of 4.68. So about 20K increase in size by calling new? Can someone explain, and sugggest a workaround? (The contract size of the BKopyLite contract is about 17k)
The new keyword results in a new contract being deployed and this requires access to its bytecode. To do this the compiler embeds BKopyLite's bytecode inside the parent contract. If the contract to be deployed is fairly big, it can add a lot to the size of the parent contract.
There are ways to avoid that:
You could for example have a special factory contract, whose only job is deploying copies of BKopyLite. The parent contract would make an external call to it to trigger deployment of BKopyLite and receive an address of a new instance in return.
You could deploy a single instance of the contract and use OpenZeppelin's Clones to create lightweight "copies". The copies would actually be proxy contracts that have their own storage and let the single instance operate on it via DELEGATECALL.
I'd like to expand on #cameel's answer which was very useful to me but took me a bit to understand.
I had a Wrapper contract which deployed instances of some contract ContractC. That means Wrapper calls new ContractC() and it takes all of ContractC's size. Not cool, it took me over the limit.
So I added a Deployer on the middle, who has a single method to deploy instances of ContractC and can only be called by Wrapper. I also added an interface for Deployer: IDeployer, which includes only the deploy method.
Wrapper keeps having all the validation logic but now does IDeployer(d_instance).deploy() instead of calling new, so it only needs to add the bytes of IDeployer, which are few. Wrapper now is way below the limit.
Init flow looks like this:
I deploy an instance of Wrapper and Deployer -> wrapper and deployer.
I tell deployer that only wrapper can call it, and I tell Wrapper who it's deployer partner is (deployer).
On every future call the flow is:
User calls wrapper.deploy()
wrapper does some validations
wrapper calls deployer.deploy()
deployer calls contractC = new ContractC()
deployer transfers ownership of contractC back to wrapper and returns it's address.
wrapper does some more logic with contractC's address
Everyone is happy.
Related
I wrote upgradable smart contract using solidity and upgraded contract several time.
When I upgraded smart contract, implementation contract address was changed.
But under that address, the old implementation contract address still remains.
https://rinkeby.etherscan.io/address/0x245dBBE31f33569D3d7F1e0df10c93547c44065D#readProxyContract
How to change or hide this old address?
Particularly you can't hide anything once it is stored on the Blockchain. The old address will still be visible.
But if you want that calling to the old contract should fail, you can simply create a self destruct function inside your smart contract and call it when you have updated the smart contract and deployed it with a new address.
Tip -
Always have smart contracts with the self destruct functionality
Whenever you update your smart contract i.e deploy it to a new address, call the self destruct function on the old contract address for it to be destroyed.
Syntax for self destruct -
contract YourContract {
// State variables
// Some functions
function destruct(address addr) ownerOnly {
selfdestruct(addr);
}
// The above function sends all ether from the contract to the specified address
}
When looking at other team's smart contracts, I often see code like this:
address constant public token = address(0xabc123...);
Where the hexadecimal number is the address of an earlier-deployed smart contract. Coming from JS and C++ background, I'm not a fan of this because it effectively hardcodes what should be in a configuration file directly into the smart contract code. Several questions come to mind when I see code like this:
What if I want to deploy this to another EVM-compatible network?
What if I want to deploy this to testnet?
I'm still relatively new to Solidity, so it's possible I'm missing some feature of truffle that allows me to insert these strings at the time of deployment, but I didn't see this mentioned in any of the tutorials I went through. I would much rather have something like a JSON configuration file for testnet/mainnet/L2-chain/etc instead of having N versions of the same file with minor differences. How should I handle these cases?
You can have a variable (instead of a constant) containing the token address. And this variable can be set from a constructor.
So you can effectively pass the value from an environment variable to the contract constructor, to the contract storage.
Example:
.env
TOKEN_ADDRESS=0x123
deploy.js using Truffle (docs) for example
MyContract.new(process.env.TOKEN_ADDRESS)
You can also use Hardhat (docs) or any other library allowing you to deploy to any network depending on the config.
MyContract.sol
pragma solidity ^0.8;
contract MyContract {
address token;
constructor(address _token) {
token = _token;
}
}
I have a Solidity smart contract which relies on Chainlink oracles for external data that has a lot of functionality code that does not need to be replicated on a per contract basis but does change the state of the contract instance, which is why I decided the proxy pattern using delegate calls makes the most sense. In the proxy pattern I only have to deploy the byte-code for my contracts functions once, and then all other instances of my contract will just delegate call to the implementation contract, and the only new information added to the block chain will be instance fields of that specific contract.
I am able to get an implementation contract deployed and point my deployed proxy to its functions, but then when I call the lock function on the proxy I fail the check require(owner == msg.sender,"Owner only") which doesnt make sense since delegate calls are supposed to pass msg.sender and I set the owner field to msg.sender in the proxy's constructor. If I remove the require, I can call the function without a revert but the locked and debugAddr fields are unchanged, even though the lock function should change them(I thought delegate call was executed in the context of the caller?). Does anyone know what is wrong with my proxy and implementation contracts? I can guess it is to do with memory layouts or the assembly im using to do delegate calls, but I am not yet on the level where I can use my googling skills to find out what is wrong, so if someone can spot where my proxy contract is incorrect/badly formatted please let me know.
Thanks,
Ben
Lock function code snippet
//Locks in the contract, buyer should have already provided data scientist an upload only API key and their model ID
function lock() public returns (bool success)
{
debugAddr = msg.sender;
uint tempStamp = now;
//THIS IS THE REQUIRE THAT FAILS WHEN IT SHOULDNT WHEN I UNCOMMENT THIS AND DEPLOY/RUN
require(msg.sender == owner, "Only owner can lock contract.");
//require(!locked, "Cannot lock contract that is already locked.");
//require(buyer != address(0),"No buyer to lock.");
//require(bytes(buyerModelName).length != 0,"No buyerModelName to lock.");
//require((tempStamp - startTimestamp) < 158400,"Cannot lock contract that was entered by buyer over 44 hours ago.");
//require((getWeekday(tempStamp) == 0) || (getWeekday(tempStamp) == 1 && getHour(tempStamp) < 14),"Contract can only be locked in between Sunday 00:00 UTC and Monday 14:00 UTC");
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
//require(link.balanceOf(address(this)) >= totalFee, "Contract requires 0.5 LINK total to operate once locked, current LINK balance is under 0.5.");
locked = true;
return true;
}
Proxy contract with require commented(also see the contract's txs, you can see me call lock):
https://kovan.etherscan.io/address/0x1f805d559f6eb7d7b19bf0340db288503f448ae8
Implementation contract the proxy points to:
https://kovan.etherscan.io/address/0xfb41ea6452da396279cbd9d9d8c136121e38fab6
Proxy contract with require uncommented(also see the contract's txs, you can see me call lock, and the revert):
https://kovan.etherscan.io/address/0x2d59aa0c1dd9a77d592167c43f2e65adcb275bfe
Implementation contract the proxy points to:
0x20a1f27d69f7a257741eddaec433642194af0215
Proxy Code and Implementation Code
Referenced Code: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Proxy.sol
Proxy: https://github.com/benschreyer/Steak/blob/main/SteakQuarterly/ProxyPattern/SteakQuarterlyProxy.sol
Important Note In my proxy I do not want to declare the contract as a ChainlinkClient since then ChainlinkClient's functions will be included in the proxy which is unnecessary as the implementation should have those methods already. Instead I only declare the fields and of ChainlinkClient on my own. I feel like this is a prime place for my implementation to be wrong, but I am not sure what needs to change/if this is even feasible
Implementation: https://github.com/benschreyer/Steak/blob/main/SteakQuarterly/ProxyPattern/SteakQuarterlyDelegate.sol
EDIT: MINIMAL CODE EXAMPLE THAT STILL FAILS
This contract should have the minimal requirements to be a proxy for a ChainlinkClient and only has the lock function and a constructor, I get the same revert on require(owner == msg.sender). If I remove the require, the call to lock on the proxy contract says confirmed, but the proxy's state variables remain unchanged (debugAddr is 0, locked stays false)
Here is the minimal example code(I deployed on remix IDE compiled 0.6.12, the proxy's lock function was called by using at address retrieval with the delegate code compiled so that the abi of the delegate is used): https://github.com/benschreyer/Steak/tree/main/MinimalCodeExample
EDIT 2:
If I remove the ChainlinkClient portion/fields of my proxy and implementation minimum examples as linked above, I get a proxy contract that works and can accept external function calls defined in the implementation contract as it should.
So my question now is how do I write proxy and implementation contract that supports Chainlink GET request functionality? What fields/constants/events/interfaces does my proxy need defined or imported and where should I define/import them to allow for Chainlink to work? For example if I wanted to have my contract retrieve the temperature in Paris from an API via Chainlink, but also be a proxy so that I do not have to redploy all its functions and save on gas price.
Anything I have tried so far(see minimal breaking example) does not work once I add Chainlink into the mix, as I am not sure about how to structure the Proxy contract class so that the storage of the proxy and the access/write of the delegate call to the implementation line up. Here is the minimal code that works after I remove Chainlink functionality:
https://github.com/benschreyer/Steak/tree/main/MinimalCodeExample/WorkingButNoChainlink
A version of my working example proxy/implementation pattern contracts but with Chainlink functionality, or pointers on what fields/events/cosntant the proxy contract needs in order for it to make calls to oracles would be much appreciated.
Instead of defining the fields of ChainlinkClient in your proxy class, write a class ChainlinkClientStorage that holds the fields of ChainlinkClient, then declare your Proxy as inheriting from ChainlinkClientStorage
https://github.com/benschreyer/Steak/blob/main/SteakQuarterly/ProxyPattern/ChainlinkClientStorage.sol
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Proxy.sol
contract MyProxy is ChainlinkClientStorage, MyContractStorage{}
In my AspNetCore application, I process messages that arrive from a queue. In order to process a message, I need to resolve some services. Some of those services have a dependency on ITenantId, which I bind using information from the received message. To solve this, the processing of a messages starts with the creation of a child container, which I then use to create an IServiceScope from which I resolve all the needed dependencies.
The messages can be processed in parallel, so the scopes must be isolated from each other.
I can see to ways of creating the child container, but I'm not sure which is best in terms of performance, memory chrurn etc:
Option A: Each time a message arrives, clone the IServiceCollection into a new ServiceCollection, and rebind ITenantId on the cloned instance.
Option B: When the program starts, create an immutable copy of the IServiceCollection (using ImmutableList<ServiceDescriptor> or ImmutableArray<ServiceDescriptor>). Each time a message arrives, replace ITenantId (resulting in a new instance of ImmutableList<ServiceDescriptor>) and call CreateScope() on the new immutable instance.
The thing I don't like about option A is that the whole collection of services needs to be cloned every time a message arrives. I'm not sure if the immutable collections in option B handles this in a smarter way?
Both options cause the creation of a new container instance for each incoming messages. Although this allows each message to run in a completely isolated bubble, this has severe implications on performance and memory use of the application. Creating container instances is expensive and resolving a registered instance for the first time (per container) causes generation of expression trees, compilation of delegates, and JIT compiling them. This can even cause memory leaks.
Besides, it also means that any registered singleton class, will have a lifetime that equals that of any scoped classes. State can't be shared any longer.
So instead, I propose Option 3:
Use only one Container instance and don't call BuildProvider more than once
Create a ITenantId implementation that allows setting the Id after instantiation
Register that implementation as Scoped
At the start of every new IServiceScope, resolve that implementation and set its id.
This might look as follows:
// Code
class TenentIdImpl : ITenantId
{
public Guid Id { get; set; } // settable
}
// Startup:
services.AddScoped<TenentIdImpl>();
services.AddScoped<ITenantId>(c => c.GetRequiredService<TenantIdImpl>());
// In message pipeline
using (var scope = provider.CreateScope())
{
var tenant = scope.ServiceProvider.GetRequiredService<TenantIdImpl>();
tenant.Id = messageEnvelope.TenantId;
var handler =
scope.ServiceProvider.GetRequiredService<IMessageHandler<TMessage>>();
handler.Handle(messageEnvelope.Message);
}
This particular model, where you store state inside your object graph, which I explain in my blog, is called the Closure Composition Model.
Sorry for the long question in the first place. I would rather prefer to come up with a shorter question but this is the most stripped version I could provide that I can clearly explain my point.
I have been trying to deliver a wrapper service to our client which should provide multiple services in it. Idea behind it is to reduce multiple calls to a one call and return a single object which has other associated objects in it. To illustrate my point, let me give following example:
Let's say we have following services:
MyCompany.Services.Donation
MyCompany.Services.Payment
MyCompany.Services.PartialPayment
Normally client should query Donation service (with a donationID) to get donation information, and then using the retrieved donation information, they should query Payment service to get payment related details, and if the payment is done in multiple small payments, using retrieved payment information, they should query PartialPayment service to get all donation information for a particular Donor.
Instead of client doing this, I am going to provide a wrapper service to accept donationID as a single parameter and return a class similar to this:
[DataContract(Namespace = "http://MyCompany.Services.DonationDetail")]
public class DonationDetail
{
[DataMember]
public MyCompany.Services.Donation.Record donationRecord;
[DataMember]
public PaymentDetail paymentDetail;
}
[DataContract(Namespace = "http://MyCompany.Services.DonationDetail")]
public class PaymentDetail
{
[DataMember]
public MyCompany.Services.Payment.Record paymentRecord;
[DataMember]
public List<MyCompany.Services.PartialPayment.Record> partialPayments;
}
So an instance of DonationDetail record should return all relevant information with that donation.
My problem arises when I use these individual services DLL's* in my wrapper service since any class I pass to client using wrapper service becomes part of the wrapper service and client can't use them right away with the corresponding types they retrieved using service references without writing a custom construction method to convert one type to another - although they are same objects. Instead of referring classes in original namespace, service uses following classes something like that now for the classes mentioned above:
DonationDetail.Record (Donation Record - I would expect MyCompany.Services.Donation.Record)
DonationDetail.Record1 (Payment Record - I would expect MyCompany.Services.Payment .Record)
DonationDetail.Record2 (PartialPayment Record - I would expect MyCompany.Services.PartialPayment.Record)
Is there a way to provide such an interface without a custom constructor? So, if they use "PartialPayment" namespace for the MyCompany.Services.PartialPayment WCF service, can they do something below after DonationDetail is retrieved via wrapper service?
PartialPayment.Record partialPayment = dDetailObj.paymentDetail.partialPayments[0];
*: Don't ask me why I don't use service references unless that is the cause of the problem, since that option gives me other problems to me at this point)
So I think what you are saying, effectively, is that if you have two different services that return the same object and when you add this as two different service references to the client, even though ultimately they are the same object as far as the services are concerned (since they reference the same DLL), the client sees them as two different types so you can't take the object returned from one and send it as the input to the other service.
Assuming I have understood your question (and I apologise if I have not)...
You could map one type to the other by constructing it and setting the properties but that is really kind of a pain and not very friendly to the consumer etc, hence I am going to suggest something kind of radical...
Ditch the service references on the client.
Yup, I said it, why would I suggest such a thing!?! Here's why...
First of all I would make sure my project was structured something like this:
Donation Detail Client Library
IDonationService (this is the service contract - notice no implementation in the client library)
DonationRecord
Payment Detail Client Library
IPaymentService (this is the service contract - notice no implementation in the client library)
PaymentRecord
Partial Payment Client Library
IPartialPaymentService (this is the service contract - notice no implementation in the client library)
PartialPaymentRecord
Wrapper Service Client Library (which references the three other client libraries)
IWrapperService (this is the service contract - notice no implementation in the client library)
Incidentally, I gave your records different class names but you could use namespaces if you like and call them all Record (I think calling them different names is less confusing, but that is probably just me).
On the service end you reference the client library that you need to implement the service and do whatever you have to do just as you always have.
On the client you reference the client libary (or libraries depending on what service you want to call) too, in the same way (so you effectively have a shared library between server and client - yeah old skool, but hey, you will see why).
The client then has the interface for the service contract and all the data contracts so it does not need the whole service reference, generated code thing. Instead what you can do on your client is something like this:
DonationRecord donation;
using (var cf = new ChannelFactory<IDonationService>("EndpointNameInConfigurationFile"))
{
IDonationService donationservice = cf.CreateChannel();
donation = donationservice.GetDonation("Donation1234");
}
using (var cf = new ChannelFactory<IWrapperService>("EndpointNameInConfigurationFile"))
{
IWrapperService wrapperService = cf.CreateChannel();
wrapperService.DoSomethingWithDonation(donation);
}
There, you see I took the data contract from one service and sent it to a completely unrelated service and it looks natural (I have an object that is returned from a method on class X and I took it and passed it as an agrument on class Y, job done, just like programming).
NOTE: Using this technique will not stop service references from working just as they always have so any existing client code would not have to change, just if you use your new wrapper service, you could use it like this to save having to map types.