EVM(Solidity) "read" in "write" behavior - solidity

Let's see a Solidity pseudocode example:
function myFunction() external payable onlyOwner {
ExternalContract contract = ExternalContract(address);
uint result = contract.readFunction();
required(result > 0, 'might failed here') //if FALSE transaction not executing at all (works as **view**)
myCustomWriteLogic();
}
The gas fee will NOT be charged if required() will fail.
Is that mean I'm performing "READ" to the blockchain and then putting the transaction to txpool?
How to force push the transaction to txpool? In my case, I belive that result willl be >0 at the execution moment.
I'm executing a transaction via truffle and I want to push it EVEN it might failed:
const obj = await MyContract.deployed();
obj.myFunction({value: 1000});

The gas fee will NOT be charged if required() will fail.
This is correct only if the snippet is invoked using a (read-only) call. If it's invoked using a transaction, gas fees will be deducted for executing of the code until the point where the require() condition fails and produces a revert.
Calls do not go through the mempool, they are executed directly on the node that you're connected to.
How to force push transaction if your wallet recommends you to not send it (as it might fail)? That depends on the specific wallet or code that you're using to broadcast the transaction. For example the MetaMask UI shows a button to force sending the transaction - see the screenshot:

Related

When sending ether to another contract it sends it to the contract?

I try to send ether from one address to another. But in the transaction the receiver seems to be the contract address.
My goal is to send from address 1 to address 2:
address1:0xDb7c83d499787E6b7660C961F8a9999E3C395AdE
address2:0x9199D9323b25BA171De6b9189201Bb322Ba12274
contract-address:0xa82bcf321f584fe81e2e3cfb04eae97b422a4c4f
But the receiver in the transaction appears to be the contract: https://blockscout.mantis.hexapod.network/tx/0x9bc22ad45dbf60881151c3b94b3d3daa98bc84b1906f1ed131ee2ca9a89484eb/internal-transactions
Function:
function sendMoney() public payable {
address payable seller = payable(0x9199D9323b25BA171De6b9189201Bb322Ba12274);
seller.transfer(msg.value);
}
When you're invoking the sendMoney() function, you're sending a transaction to the contract that implements this function.
The seller.transfer(msg.value); is an internal transaction - a part of the main transaction.
I had the same problem. But it is actually working fine, the ether is sent. My mistake was that I didn't change the denomination of ether, it was set to wei. So, I was trying to send 1 wei instead of 1 ether. The transaction goes through but I couldn't see the change as the quantity was so small.

Debugging "Transaction simulation failed" when sending program instruction (Solana Solidity)

When attempting to make a call to a program compiled with #solana/solidity, I'm getting the following error:
Transaction simulation failed: Error processing Instruction 0: Program failed to complete
Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N invoke [1]
Program log: pxKTQePwHC9MiR52J5AYaRtSLAtkVfcoGS3GaLD24YX
Program log: sender account missing from transaction
Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N consumed 200000 of 200000 compute units
Program failed to complete: BPF program Panicked in solana.c at 285:0
Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N failed: Program failed to complete
jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N is the program's public key and pxKTQePwHC9MiR52J5AYaRtSLAtkVfcoGS3GaLD24YX is the sender's public key.
I'm using a fork of the #solana/solidity library that exposes the Transaction object so that it can be signed and sent by Phantom Wallet on the front end. The code that results in the error is as follows:
// Generate the transaction
const transaction = contract.transactions.send(...args);
// Add recent blockhash and fee payer
const recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
transaction.recentBlockhash = recentBlockhash;
transaction.feePayer = provider.publicKey;
// Sign and send the transaction (throws an error)
const res = await provider.signAndSendTransaction(transaction);
I would attempt to debug this further myself, but I'm not sure where to start. Looking up the error message hasn't yielded any results and the error message isn't very descriptive. I'm not sure if this error is occurring within the program execution itself or if it's an issue with the composition of the transaction object. If it is an issue within the program execution, is there a way for me to add logs to my solidity code? If it's an issue with the transaction object, what could be missing? How can I better debug issues like this?
Thank you for any help.
Edit: I'm getting a different error now, although I haven't changed any of the provided code. The error message is now the following:
Phantom - RPC Error: Transaction creation failed. {code: -32003, message: 'Transaction creation failed.'}
Unfortunately this error message is even less helpful than the last one. I'm not sure if Phantom Wallet was updated or if a project dependency was updated at some point, but given the vague nature of both of these error messages and the fact that none of my code has changed, I believe they're being caused by the same issue. Again, any help or debugging tips are appreciated.
I was able to solve this issue, and although I've run into another issue it's not related to the contents of this question so I'll post it separately.
Regarding my edit, I found that the difference between the error messages came down to how I was sending the transaction. At first, I tried sending it with Phantom's .signAndSendTransaction() method, which yielded the second error message (listed under my edit). Then I tried signing & sending the transaction manually, like so:
const signed = await provider.request({
method: 'signTransaction',
params: {
message: bs58.encode(transaction.serializeMessage()),
},
});
const signature = bs58.decode(signed.signature);
transaction.addSignature(provider.publicKey, signature);
await connection.sendRawTransaction(transaction.serialize())
Which yielded the more verbose error included in my original post. That error message did turn out to be helpful once I realized what to look for -- the sending account's public key was missing from the keys field on the TransactionInstruction on the Transaction. I added it in my fork of the #solana/solidity library and the error went away.
In short, the way I was able to debug this was by
Using provider.request({ method: 'signTransaction' }) and connection.sendRawTransaction(transaction) rather than Phantom's provider.signAndSendTransaction() method for a more verbose error message
Logging the transaction object and inspecting the instructions closely
I hope this helps someone else in the future.

In my js file for testing .I call a send transaction to the smart contract, so what is the difference between value and gas :

it("allows a manager to make a payment request f(createRequest) ", async ()=> {
await campaign.methods.createRequest('buy beer', accounts[2], '100').send({
from: accounts[0],
gas: '1000000'
});
it('Contribute money from another account & checks whether it is approved or not', async () =>{
await campaign.methods.contribute().send({
from: accounts[1],
value: '200'
});
I want to know deciding factors, when to use gas and when to use value?
value is the amount of the native token that you send with the transaction.
Network
Native token
Ethereum
ETH
Binance Smart Chain
BNB
Tron
TRX
It's expressed in the smallest non-divisible unit. In case of ETH, that's wei. 1 ETH is 10^18 wei.
So as per your example, when you set the value to 200, you're going to send along 0.0000000000000002 ETH to the contract with the execution of the contribute() function.
An example use of the value is when a contract wants to sell you a token for 0.1 ETH. In this case, you set the value to 0.1 ETH while executing the contract's buy() function.
The value does NOT replace the gas fee:
gas is the amount of the fee that you send along with the transaction. For better explanation, what gas is, there's a great post on the Ethereum StackExchange.
But in short - gas is a way of payment for the execution of the smart contract function.
The minimal amount of gas required to execute the function can be usually calculated using the web3 estimateGas() method (there are some exceptions when the estimate is incorrect or impossible to calculate).
Depending on the gasPrice (that's either calculated automatically from recent data or you can overwrite it manually), the total transaction fee is calculated in the native token (e.g. ETH).

How does full node verify transaction if all it has bitcoin address and no public key

If it’s impossible to get public address from bitcoin address. How can a full node performing the transaction verify that the transaction is coming from authorised user.
The core of bitcoin is he language, Bitcoin Script, this is a language not Turing complete because is without loop.
The node bitcoin doesn't need the public key for spending the bitcoin, but a transaction input have an unlocked script (known as ScriptSig) this transaction can unlock a previous output transaction with have a locked script(Know as Script pubkey), for unlocked the node executed in the stack the ScriptSig + ScrptPubKey, if return true the transaction is spendable otherwise no.
an example
if you have two transaction
Input:
Previous tx: f5d8ee39a430901c91a5917b9f2dc19d6d1a0e9cea205b009ca73dd04470b9a6
Index: 0
scriptSig: 304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d10
90db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501
Output:
Value: 5000000000
scriptPubKey: OP_DUP OP_HASH160 404371705fa9bd789a2fcd52d2c580b65d35549d
OP_EQUALVERIFY OP_CHECKSIG
How bitcoin execute the script
Complete script
304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d10 OP_DUP OP_HASH160 404371705fa9bd789a2fcd52d2c580b65d35549d OP_EQUALVERIFY OP_CHECKSIG
if you push the script inside this ide and run it you can see how bitcoin run the script.
In this example the ide returned false because the transaction output cannot be sent with her input
The ScriptPubKey(most of the time) contains the pubKey
The ScriptSing contains the Signature of the private key
This are all informations for work the simple node bitcoin.
Now I have and question for you.
You say
impossible to get public address from bitcoin address.
what does it mean?

Suppressing NServicebus Transaction to write errors to database

I'm using NServiceBus to handle some calculation messages. I have a new requirement to handle calculation errors by writing them the same database. I'm using NHibernate as my DAL which auto enlists to the NServiceBus transaction and provides rollback in case of exceptions, which is working really well. However if I write this particular error to the database, it is also rolled back which is a problem.
I knew this would be a problem, but I thought I could just wrap the call in a new transaction with the TransactionScopeOption = Suppress. However the error data is still rolled back. I believe that's because it was using the existing session with has already enlisted in the NServiceBus transaction.
Next I tried opening a new session from the existing SessionFactory within the suppression transaction scope. However the first call to the database to retrieve or save data using this new session blocks and then times out.
InnerException: System.Data.SqlClient.SqlException
Message=Timeout expired. The timeout period elapsed prior to completion of the >operation or the server is not responding.
Finally I tried creating a new SessionFactory using it to open a new session within the suppression transaction scope. However again it blocks and times out.
I feel like I'm missing something obvious here, and would greatly appreciate any suggestions on this probably common task.
As Adam suggests in the comments, in most cases it is preferred to let the entire message fail processing, giving the built-in Retry mechanism a chance to get it right, and eventually going to the error queue. Then another process can monitor the error queue and do any required notification, including logging to a database.
However, there are some use cases where the entire message is not a failure, i.e. on the whole, it "succeeds" (whatever the business-dependent definition of that is) but there is some small part that is in error. For example, a financial calculation in which the processing "succeeds" but some human element of the data is "in error". In this case I would suggest catching that exception and sending a new message which, when processed by another endpoint, will log the information to your database.
I could see another case where you want the entire message to fail, but you want the fact that it was attempted noted somehow. This may be closest to what you are describing. In this case, create a new TransactionScope with TransactionScopeOption = Suppress, and then (again) send a new message inside that scope. That message will be sent whether or not your full message transaction rolls back.
You are correct that your transaction is rolling back because the NHibernate session is opened while the transaction is in force. Trying to open a new session inside the suppressed transaction can cause a problem with locking. That's why, most of the time, sending a new message asynchronously is part of the solution in these cases, but how you do it is dependent upon your specific business requirements.
I know I'm late to the party, but as an alternative suggestion, you coudl simply raise another separate log message, which NSB handles independently, for example:
public void Handle(DebitAccountMessage message)
{
var account = this.dbcontext.GetById(message.Id);
if (account.Balance <= 0)
{
// log request - new handler
this.Bus.Send(new DebitAccountLogMessage
{
originalMessage = message,
account = account,
timeStamp = DateTime.UtcNow
});
// throw error - NSB will handle
throw new DebitException("Not enough funds");
}
}
public void Handle(DebitAccountLogMessage message)
{
var messageString = message.originalMessage.Dump();
var accountString = message.account.Dump(DumpOptions.SuppressSecurityTokens);
this.Logger.Log(message.UniqueId, string.Format("{0}, {1}", messageString, accountString);
}