Solana metaplex auction fails in ValidateSafetyDepositBoxV2 instruction with "Supplied an invalid creator index to empty payment account" - flutter

I'm porting metaplex auction-house to Flutter mobile.
When creating auction with instant sale price of 0.1 wrapped sol, I have encountered the following error at the stage of ValidateSafetyDepositBoxV2 instruction.
The error was "Supplied an invalid creator index to empty payment account" and there is only one point where this message can be printed is Rust's process_empty_payment_account().
The most weird thing is that process_empty_payment_account function is called only from EmptyPaymentAccount instruction and my program didn't call it.
any idea what's happening?
Actual error log:
I/flutter ( 2718): {accounts: null, err: {InstructionError: [0, {Custom: 63}]}, logs: [Program p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98 invoke [1], Program log: Instruction: Validate Safety Deposit Box V2, Program log: Supplied an invalid creator index to empty payment account, Program p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98 consumed 11849 of 200000 compute units, Program p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98 failed: custom program error: 0x3f], unitsConsumed: 0}

I found the reason why that error was given after deploying a new program with some logs to the rust program. It was that I passed the wrong value for the metadata's address as the 4th account.
pub fn process_validate_safety_deposit_box_v2<'a>(
program_id: &'a Pubkey,
accounts: &'a [AccountInfo<'a>],
safety_deposit_config: SafetyDepositConfig,
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let safety_deposit_config_info = next_account_info(account_info_iter)?;
let auction_token_tracker_info = next_account_info(account_info_iter)?;
let mut auction_manager_info = next_account_info(account_info_iter)?;
*let metadata_info = next_account_info(account_info_iter)?;*
....
So, the program failed at Metadata::try_from_slice_checked and returns error of InvalidCreatorIndex at the following code.
impl Metadata {
pub fn from_account_info(a: &AccountInfo) -> Result<Metadata, ProgramError> {
let md: Metadata =
try_from_slice_checked(&a.data.borrow_mut(), Key::MetadataV1, MAX_METADATA_LEN)?;
Ok(md)
}
}
It's a pity that the code didn't give a more elaborate error.

Related

channelRead not being called in Swift-NIO Datagram's ChannelInboundHandler

I am trying to capture a UDP video stream within a (fresh) vapor application running in Xcode. The data is being streamed by ffmpeg and I can successfully view the stream on the target machine using VLC, which is also the one running the vapor application, using udp://0.0.0.0:5000. I have used various bits of Apple documentation to get to the code below. When I run it, I get these lines of output on the console log, but I wonder if they are not relevant:
2021-07-07 17:59:27.102681+0100 Run[10550:2494617] [si_destination_compare] send failed: Invalid argument
2021-07-07 17:59:27.104056+0100 Run[10550:2494617] [si_destination_compare] send failed: Undefined error: 0
In configure.swift:
try setupClient()
This is the client code:
final class FrameHandler : ChannelInboundHandler {
typealias InboundIn = AddressedEnvelope<ByteBuffer>
typealias OutboundOut = AddressedEnvelope<ByteBuffer>
func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
// minimal for question
}
func errorCaught(ctx: ChannelHandlerContext, error: Error) {
// minimal for question
}
}
func setupClient() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let bootstrap = DatagramBootstrap(group: group)
.channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.channelInitializer { channel in
channel.pipeline.addHandler(FrameHandler())
}
defer {
try! group.syncShutdownGracefully()
}
let channel = try bootstrap.bind(host: "0.0.0.0", port: 5000).wait()
try channel.closeFuture.wait()
}
The problem is that although channelRegistered and channelActive are called, followed by a never-ending stream of readComplete, the important one channelRead never gets called - neither does errorCaught. If I comment out the call to setupClient then there is no network activity, however, if it runs then Xcode's network monitor shows activity consistent with the levels in ffmpeg. So, I believe the connection is being set up.
I wonder if the problem is in the way I am setting the handler up? All the examples use echo or reflecting chat examples, so the inbound handler is set up in the closure of the data-writing function using the context rather than adding it in the initialiser (although, the outbound handler is set up in this way).
I'm assuming you're using Vapor 4 which is based on SwiftNIO 2. And in NIO 2, the ChannelHandlerContext variable is called context and not ctx. So if you just rename all your ctx to context, I'd assume it'll work.

Google text-to-speech - Google::Cloud::InternalError (13:Internal error encountered.):

I have Google Text to Speech up and running in my application. Most of the time the API works perfectly, and I'm receiving audio file responses that play fine.
Sometimes though I receive the following error:
Google::Cloud::InternalError (13:Internal error encountered.):
I have safeguards in place to prevent my app from running into usage quotas so I don't think it's that. Also, before I had these safeguards in place, if I did go over quotas the error messages said you were over your quota.
Does anyone know what this message means?
Alternatively, if someone knows a good way to handle this error gracefully (it's a Rails app).
Thanks
Ok so I don't know what exactly is going wrong on Google's side other than some sort of internal error. However, I did come up with a solution to rescue the error and allows me to continue my text to speech job.
Here is what my code looks like for those interested:
def convert_to_audio(text, gender)
client = Google::Cloud::TextToSpeech.text_to_speech
input_text = { text: text }
# Note: the voice can also be specified by name.
# Names of voices can be retrieved with client.list_voices
# https://cloud.google.com/text-to-speech/docs/voices
if gender == 'MALE'
name = 'en-US-Standard-D'
else
name = 'en-US-Standard-E'
end
voice = {
language_code: "en-US",
name: name,
ssml_gender: gender
}
audio_config = { audio_encoding: "MP3" }
begin
retries ||= 0
response = client.synthesize_speech(
input: input_text,
voice: voice,
audio_config: audio_config
)
rescue Google::Cloud::InternalError
puts "The Google error occurred"
retry if (retries += 1) < 3
end
Basically now when I get that error from Google I retry the synthesize speech call.
Google has pretty tight quotas set on this API, and I'm guessing this is because larger and more frequent requests tend to throw errors more often, so they're trying to do quality control.
I did also find this error mapping for those interested:
namespace error {
// These values must match error codes defined in google/rpc/code.proto.
enum Code {
OK = 0,
CANCELLED = 1,
UNKNOWN = 2,
INVALID_ARGUMENT = 3,
DEADLINE_EXCEEDED = 4,
NOT_FOUND = 5,
ALREADY_EXISTS = 6,
PERMISSION_DENIED = 7,
UNAUTHENTICATED = 16,
RESOURCE_EXHAUSTED = 8,
FAILED_PRECONDITION = 9,
ABORTED = 10,
OUT_OF_RANGE = 11,
UNIMPLEMENTED = 12,
INTERNAL = 13,
UNAVAILABLE = 14,
DATA_LOSS = 15,
};
} // namespace error

Unable to properly handle errors

I have found the reason why my application isn't behaving the way I would like it to but I don't know how to resolve the issue. To summarise, my application has a custom error handler which gets invoked if there is an error. The error handler sends json messages. But in one application startup error scenario (Future fails), I want to Redirect the user to homepage instead of sending a json message.but it doesn't happen because the custom error handler sends json message before I can send a Redirect from Future's recover.
One feature of the application is signup verification. The user clicks on a url which has a token. When the url is clicked, verifyUser Action is called. It does some checks (using database queries using Futures) and depending on the success or failure, it sends Redirect with signup=success or signup=error attribute (not failure here is decided based on whether something exists in the database or not). However, if the Future fails (I queried a wrong field which is not part of database's schema), I want to Redirect again but it doesn't work as the custom error handler gets invoked before recover. How could I make my application Redirect?
val result:Future[Result] = for{tokenOption:Option[UserToken] <- userTokenRepo.findOne(UserTokenKey(UUID.fromString(token))) //generator 1 - get token from database
userOption:Option[User] <- if (tokenOption.isDefined) userRepo.findOne(tokenOption.get.userKeys) else Future.successful(None) //generator2. found token, look for corresponding user to which the token belongs
modifiedUser:Option[User] <- if (userOption.isDefined) confirmSignupforUser(userOption.get) else Future.successful(None) //generator 3. found user and token. Update profile
deletedToken:Option[UserTokenKey] <- if(modifiedUser.isDefined) userTokenRepo.delete(UserTokenKey(UUID.fromString(token))) else Future.successful(None)
}
yield { //check if we have user and token and modified user here. If any is missing, return error else success
println("db query results tokenOption: "+tokenOption+", userOption: "+userOption+" : modifiedUserOption: "+modifiedUser+", deletedToken: "+deletedToken)
if(tokenOption.isDefined && userOption.isDefined && modifiedUser.isDefined && deletedToken.isDefined)
Redirect("http://localhost:9000/home"+";signup=success")//TODOM - pick from config
else
/*TODOM - when redirecting with error, can provide additional info why sign up failed*/
if(tokenOption.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else if(userOption.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else if(modifiedUser.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else //this shouldn't happen. Unexpected
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
}
result.recover { case x => {
println("Future failed in validateUserSession. Recovering. Returning Internal Server Error" + x)
//before this Redirect, the custom error handler sends json response
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
}
}
Custom error handler
class CustomHttpErrorHandler extends HttpErrorHandler {
def onClientError(request: RequestHeader, statusCode: Int, message: String) = {
println("client error: request "+request+", statusCode: "+statusCode+", message:"+message)
Future.successful(
Status(statusCode)(Json.toJson(JsonResultError(message)))
)
}
def onServerError(request: RequestHeader, exception: Throwable) = {
println("server error: request: "+request+", exception: "+exception.getMessage)
Future.successful(
InternalServerError(Json.toJson(JsonResultError(exception.getMessage)))
)
}
}
I am able to verify the isse as I see two debugs (one from custom error handler and other from recover)
server error: request: GET /ws/users/signup/312c9eaf-f27b-43c7-8dac-445a628c3be8, exception: bucket_id is not a column defined in this metadata
Future failed in validateUserSession. Recovering. Returning Internal Server Errorjava.lang.IllegalArgumentException: bucket_id is not a column defined in this metadata
I could try to check based on the exception received in custom error handler but I think it is too generic and might not be a good design approach.
It is possible that the error is happening before the Future is created so the code is throwing an exception that is handled by the default handler rather than being caught by the Future.
Specifically, the expression
userTokenRepo.findOne(UserTokenKey(UUID.fromString(token)))
is evaluated in the current thread, so any exception in this code will not be caught and will invoke the default error handler.
The solution is to compute this in a Try and process the error immediately if there is one.
This is what it might look like:
for {
tokenKey <- Future.fromTry(Try(UserTokenKey(UUID.fromString(token))))
tokenOption <- userTokenRepo.findOne(tokenKey)
userOption <- tokenOption.fold(Future.successful)(userRepo.findOne(_.userKeys)) //generator2. found token, look for corresponding user to which the token belongs
modifiedUser <- userOption.fold(Future.successful)(confirmSignupforUser) //generator 3. found user and token. Update profile
...
Any exception in this code will result in a failed Future which your recover code will handle.

CloudKit Batch Error: Previous Error in Atomic Zone

I am attempting to save a CKRecord using a CKModifyRecordsOperation and every time I try it, I get this initial error:
["CKErrorDescription": Failed to modify some records,
"CKPartialErrors": {
"CKRecordID: 0x60c000034000; recordName=ABC, zoneID=workspaceZone:DEF" = "CKError 0x60c000257340: \"Batch Request Failed\" (22/2024); \"Record CKRecordID: 0x7fb2f6998a60; recordName=ABC, zoneID=workspaceZone:DEF will not be saved because of previous error in atomic zone\"";
},
"NSDebugDescription": CKInternalErrorDomain: 1011, "NSUnderlyingError": CKError 0x60c000248af0: "Partial Failure" (1011); "Failed to modify some records"; partial errors: {
... 1 "Batch Request Failed" CKError's omited ...
},
"NSLocalizedDescription": Failed to modify some records]
I then parse the individual errors of the batch like this:
if let errorItems = error.partialErrorsByItemID {
for item in errorItems{
if let itemError = item.value as? CKError{
print("::: Individual Error in Batch :::")
print(itemError)
print(":::::")
}
}
}
But all the individual error says is:
CKError(_nsError: CKError 0x60c000257340: "Batch Request Failed" (22/2024); "Record CKRecordID: 0x7fb2f6998a60; recordName=GHI, zoneID=workspaceZone:JKL will not be saved because of previous error in atomic zone")
The CloudKit server log just says it's a BAD_REQUEST which isn't very helpful either.
Is there a way to get more details as to what's wrong with my record?
This just means one of your requests failed. You're doing a batch request with one or more requests. If one fails, CloudKit fails all of the requests to keep things atomic.
So, you should subscribe to errors on each record with perRecordCompletionBlock. Then, you can see which record is failing and why. You should print out the userInfo dictionary of the error for more detailed information.

windows kdmf driver virtio calling virtqueue_add_buf causes system fatal error

I have a driver for Windows VM that allows user space apps to communicate via IOCTL. I need to expose a structure to the host (using virtio) and I have tried using virtqueue_add_buf after initializing the virt device in the EvtDevicePrepareHardware using VirtIODeviceInitialize function. I am getting a fatal error when calling virtqueue_add_buf.
Below is a snippet of code
int TellHost(WDFOBJECT WdfDevice, VirtioQArg *virtioArg)
{
VIO_SG sg;
PDEVICE_CONTEXT context = GetDeviceContext(WdfDevice);
sg.physAddr = MmGetPhysicalAddress(virtioArg);
sg.length = sizeof(VirtioQCArg);
WdfSpinLockAcquire(context->VirtQueueLock);
error = virtqueue_add_buf(context->VirtQueue, &sg, 1, 0, virtioArg, NULL, 0);
// more code ....
WdfSpinLockRelease(context->VirtQueueLock);
}
The error I get is Fatal System Error: 0x000000d1 (0x0000000000000014,0x0000000000000002,0x0000000000000000,0xFFFFF80109FC0637)
Break instruction exception - code 80000003 (first chance)
and then windbg is unable to load symbols and crashes making my debugging session useless. Any ideas how I can debug this or what I might be missing?
0x000000d1 is DRIVER_IRQL_NOT_LESS_OR_EQUAL which almost always means invalid address is being referenced or addressing paged memory at DPC IRQL or higher.
0x0000000000000000 is a read access to invalid address (0x0000000000000014) from IRQL 2 (DPC).
I had not initialized the queue. Thanks to Vadim RozenFeld from Redhat for pointing out my mistake and his precise explanation.
I checked the balloon virtio driver which uses the following function for initialization of virtio queue.
PVIOQUEUE FindVirtualQueue(VIODEVICE *dev, ULONG index)
{
PVIOQUEUE pq = NULL;
PVOID p;
ULONG size, allocSize;
VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize);
if (allocSize)
{
PHYSICAL_ADDRESS HighestAcceptable;
HighestAcceptable.QuadPart = 0xFFFFFFFFFF;
p = MmAllocateContiguousMemory(allocSize, HighestAcceptable);
if (p)
{
pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE);
}
}
return pq;
}