2021-01-15 23:05:26 -08:00
const assert = require ( "assert" ) ;
2021-12-15 15:11:41 -08:00
const anchor = require ( "@project-serum/anchor" ) ;
2021-06-09 13:02:50 -07:00
const { Account , Transaction , TransactionInstruction } = anchor . web3 ;
2022-03-15 08:42:17 -07:00
const { TOKEN _PROGRAM _ID , Token } = require ( "@solana/spl-token" ) ;
2021-01-15 23:05:26 -08:00
2022-02-20 14:28:24 -08:00
// sleep to allow logs to come in
const sleep = ( ms ) =>
new Promise ( ( resolve ) => {
setTimeout ( ( ) => resolve ( ) , ms ) ;
} ) ;
2022-03-15 08:42:17 -07:00
const withLogTest = async ( callback , expectedLogs ) => {
2022-02-20 14:28:24 -08:00
let logTestOk = false ;
const listener = anchor . getProvider ( ) . connection . onLogs (
"all" ,
( logs ) => {
2022-03-15 08:42:17 -07:00
const index = logs . logs . findIndex (
( logLine ) => logLine === expectedLogs [ 0 ]
) ;
if ( index === - 1 ) {
console . log ( "Expected: " ) ;
console . log ( expectedLogs ) ;
console . log ( "Actual: " ) ;
2022-02-20 14:28:24 -08:00
console . log ( logs ) ;
2022-03-15 08:42:17 -07:00
} else {
const actualLogs = logs . logs . slice ( index , index + expectedLogs . length ) ;
for ( let i = 0 ; i < expectedLogs . length ; i ++ ) {
if ( actualLogs [ i ] !== expectedLogs [ i ] ) {
console . log ( "Expected: " ) ;
console . log ( expectedLogs ) ;
console . log ( "Actual: " ) ;
console . log ( logs ) ;
return ;
}
}
logTestOk = true ;
2022-02-20 14:28:24 -08:00
}
} ,
"recent"
) ;
try {
await callback ( ) ;
} catch ( err ) {
anchor . getProvider ( ) . connection . removeOnLogsListener ( listener ) ;
throw err ;
}
await sleep ( 3000 ) ;
anchor . getProvider ( ) . connection . removeOnLogsListener ( listener ) ;
assert . ok ( logTestOk ) ;
} ;
2021-01-15 23:05:26 -08:00
describe ( "errors" , ( ) => {
// Configure the client to use the local cluster.
2022-02-20 14:28:24 -08:00
const localProvider = anchor . Provider . local ( ) ;
localProvider . opts . skipPreflight = true ;
anchor . setProvider ( localProvider ) ;
2021-01-15 23:05:26 -08:00
const program = anchor . workspace . Errors ;
it ( "Emits a Hello error" , async ( ) => {
2022-02-20 14:28:24 -08:00
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . hello ( ) ;
assert . ok ( false ) ;
} catch ( err ) {
const errMsg =
"This is an error message clients will automatically display" ;
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
assert . equal ( err . code , 6000 ) ;
}
2022-03-15 08:42:17 -07:00
} , [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:13. Error Code: Hello. Error Number: 6000. Error Message: This is an error message clients will automatically display." ,
] ) ;
2022-02-20 14:28:24 -08:00
} ) ;
it ( "Emits a Hello error via require!" , async ( ) => {
2021-01-15 23:05:26 -08:00
try {
2022-02-20 14:28:24 -08:00
const tx = await program . rpc . testRequire ( ) ;
2021-01-15 23:05:26 -08:00
assert . ok ( false ) ;
} catch ( err ) {
const errMsg =
"This is an error message clients will automatically display" ;
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
2021-12-08 13:50:08 -08:00
assert . equal ( err . code , 6000 ) ;
2021-01-15 23:05:26 -08:00
}
} ) ;
2022-02-20 14:28:24 -08:00
it ( "Emits a Hello error via err!" , async ( ) => {
try {
const tx = await program . rpc . testErr ( ) ;
assert . ok ( false ) ;
} catch ( err ) {
const errMsg =
"This is an error message clients will automatically display" ;
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
assert . equal ( err . code , 6000 ) ;
}
} ) ;
it ( "Logs a ProgramError" , async ( ) => {
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . testProgramError ( ) ;
assert . ok ( false ) ;
} catch ( err ) {
// No-op (withLogTest expects the callback to catch the initial tx error)
}
2022-03-15 08:42:17 -07:00
} , [
"Program log: ProgramError occurred. Error Code: InvalidAccountData. Error Number: 17179869184. Error Message: An account's data contents was invalid." ,
] ) ;
2022-02-20 14:28:24 -08:00
} ) ;
it ( "Logs a ProgramError with source" , async ( ) => {
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . testProgramErrorWithSource ( ) ;
assert . ok ( false ) ;
} catch ( err ) {
// No-op (withLogTest expects the callback to catch the initial tx error)
}
2022-03-15 08:42:17 -07:00
} , [
"Program log: ProgramError thrown in programs/errors/src/lib.rs:38. Error Code: InvalidAccountData. Error Number: 17179869184. Error Message: An account's data contents was invalid." ,
] ) ;
2022-02-20 14:28:24 -08:00
} ) ;
2021-01-15 23:05:26 -08:00
it ( "Emits a HelloNoMsg error" , async ( ) => {
try {
const tx = await program . rpc . helloNoMsg ( ) ;
assert . ok ( false ) ;
} catch ( err ) {
const errMsg = "HelloNoMsg" ;
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
2021-12-08 13:50:08 -08:00
assert . equal ( err . code , 6000 + 123 ) ;
2021-01-15 23:05:26 -08:00
}
} ) ;
it ( "Emits a HelloNext error" , async ( ) => {
try {
const tx = await program . rpc . helloNext ( ) ;
assert . ok ( false ) ;
} catch ( err ) {
const errMsg = "HelloNext" ;
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
2021-12-08 13:50:08 -08:00
assert . equal ( err . code , 6000 + 124 ) ;
2021-06-09 13:02:50 -07:00
}
} ) ;
it ( "Emits a mut error" , async ( ) => {
2022-02-20 14:28:24 -08:00
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . mutError ( {
accounts : {
myAccount : anchor . web3 . SYSVAR _RENT _PUBKEY ,
} ,
} ) ;
assert . ok ( false ) ;
} catch ( err ) {
const errMsg = "A mut constraint was violated" ;
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
assert . equal ( err . code , 2000 ) ;
}
2022-03-15 08:42:17 -07:00
} , [
"Program log: AnchorError caused by account: my_account. Error Code: ConstraintMut. Error Number: 2000. Error Message: A mut constraint was violated." ,
] ) ;
2021-06-09 13:02:50 -07:00
} ) ;
2021-07-03 11:58:23 -07:00
it ( "Emits a has one error" , async ( ) => {
2021-06-09 13:02:50 -07:00
try {
const account = new Account ( ) ;
2021-07-03 11:58:23 -07:00
const tx = await program . rpc . hasOneError ( {
2021-06-09 13:02:50 -07:00
accounts : {
myAccount : account . publicKey ,
owner : anchor . web3 . SYSVAR _RENT _PUBKEY ,
rent : anchor . web3 . SYSVAR _RENT _PUBKEY ,
} ,
instructions : [
2021-07-03 11:58:23 -07:00
await program . account . hasOneAccount . createInstruction ( account ) ,
2021-06-09 13:02:50 -07:00
] ,
signers : [ account ] ,
} ) ;
assert . ok ( false ) ;
} catch ( err ) {
2021-07-03 11:58:23 -07:00
const errMsg = "A has_one constraint was violated" ;
2021-06-09 13:02:50 -07:00
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
2021-12-08 13:50:08 -08:00
assert . equal ( err . code , 2001 ) ;
2021-06-09 13:02:50 -07:00
}
} ) ;
// This test uses a raw transaction and provider instead of a program
// instance since the client won't allow one to send a transaction
// with an invalid signer account.
it ( "Emits a signer error" , async ( ) => {
2022-02-20 14:28:24 -08:00
let signature ;
const listener = anchor
. getProvider ( )
. connection . onLogs ( "all" , ( logs ) => ( signature = logs . signature ) ) ;
2021-06-09 13:02:50 -07:00
try {
const tx = new Transaction ( ) ;
tx . add (
new TransactionInstruction ( {
keys : [
{
pubkey : anchor . web3 . SYSVAR _RENT _PUBKEY ,
isWritable : false ,
isSigner : false ,
} ,
] ,
programId : program . programId ,
data : program . coder . instruction . encode ( "signer_error" , { } ) ,
} )
) ;
await program . provider . send ( tx ) ;
assert . ok ( false ) ;
} catch ( err ) {
2022-02-20 14:28:24 -08:00
await sleep ( 3000 ) ;
anchor . getProvider ( ) . connection . removeOnLogsListener ( listener ) ;
const errMsg = ` Error: Raw transaction ${ signature } failed ({"err":{"InstructionError":[0,{"Custom":3010}]}}) ` ;
2021-06-09 13:02:50 -07:00
assert . equal ( err . toString ( ) , errMsg ) ;
2022-02-20 14:28:24 -08:00
} finally {
anchor . getProvider ( ) . connection . removeOnLogsListener ( listener ) ;
2021-01-15 23:05:26 -08:00
}
} ) ;
2021-10-21 15:51:20 -07:00
it ( "Emits a raw custom error" , async ( ) => {
try {
const tx = await program . rpc . rawCustomError ( {
accounts : {
myAccount : anchor . web3 . SYSVAR _RENT _PUBKEY ,
} ,
} ) ;
assert . ok ( false ) ;
} catch ( err ) {
const errMsg = "HelloCustom" ;
assert . equal ( err . toString ( ) , errMsg ) ;
assert . equal ( err . msg , errMsg ) ;
2021-12-08 13:50:08 -08:00
assert . equal ( err . code , 6000 + 125 ) ;
2021-10-21 15:51:20 -07:00
}
} ) ;
2021-11-18 07:42:07 -08:00
it ( "Emits a account not initialized error" , async ( ) => {
2022-02-20 14:28:24 -08:00
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . accountNotInitializedError ( {
accounts : {
notInitializedAccount : new anchor . web3 . Keypair ( ) . publicKey ,
} ,
} ) ;
assert . fail (
"Unexpected success in creating a transaction that should have fail with `AccountNotInitialized` error"
) ;
} catch ( err ) {
const errMsg =
"The program expected this account to be already initialized" ;
assert . equal ( err . toString ( ) , errMsg ) ;
}
2022-03-15 08:42:17 -07:00
} , [
"Program log: AnchorError caused by account: not_initialized_account. Error Code: AccountNotInitialized. Error Number: 3012. Error Message: The program expected this account to be already initialized." ,
] ) ;
} ) ;
it ( "Emits an AccountOwnedByWrongProgram error" , async ( ) => {
let client = await Token . createMint (
program . provider . connection ,
program . provider . wallet . payer ,
program . provider . wallet . publicKey ,
program . provider . wallet . publicKey ,
9 ,
TOKEN _PROGRAM _ID
) ;
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . accountOwnedByWrongProgramError ( {
accounts : {
wrongAccount : client . publicKey ,
} ,
} ) ;
assert . fail (
"Unexpected success in creating a transaction that should have failed with `AccountOwnedByWrongProgram` error"
) ;
} catch ( err ) {
const errMsg =
"The given account is owned by a different program than expected" ;
assert . equal ( err . toString ( ) , errMsg ) ;
}
} , [
"Program log: AnchorError caused by account: wrong_account. Error Code: AccountOwnedByWrongProgram. Error Number: 3007. Error Message: The given account is owned by a different program than expected." ,
"Program log: Left:" ,
"Program log: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" ,
"Program log: Right:" ,
"Program log: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" ,
] ) ;
} ) ;
it ( "Emits a ValueMismatch error via require_eq" , async ( ) => {
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . requireEq ( ) ;
assert . fail (
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
) ;
} catch ( err ) {
assert . equal ( err . code , 6126 ) ;
}
} , [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:68. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch." ,
"Program log: Left: 5241" ,
"Program log: Right: 124124124" ,
] ) ;
} ) ;
it ( "Emits a RequireEqViolated error via require_eq" , async ( ) => {
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . requireEqDefaultError ( ) ;
assert . fail (
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
) ;
} catch ( err ) {
assert . equal ( err . code , 2501 ) ;
}
} , [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:73. Error Code: RequireEqViolated. Error Number: 2501. Error Message: A require_eq expression was violated." ,
"Program log: Left: 5241" ,
"Program log: Right: 124124124" ,
] ) ;
} ) ;
it ( "Emits a ValueMismatch error via require_keys_eq" , async ( ) => {
const someAccount = anchor . web3 . Keypair . generate ( ) . publicKey ;
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . requireKeysEq ( {
accounts : {
someAccount ,
} ,
} ) ;
assert . fail (
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
) ;
} catch ( err ) {
assert . equal ( err . code , 6126 ) ;
}
} , [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:78. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch." ,
"Program log: Left:" ,
` Program log: ${ someAccount } ` ,
"Program log: Right:" ,
` Program log: ${ program . programId } ` ,
] ) ;
} ) ;
it ( "Emits a RequireKeysEqViolated error via require_keys_eq" , async ( ) => {
const someAccount = anchor . web3 . Keypair . generate ( ) . publicKey ;
await withLogTest ( async ( ) => {
try {
const tx = await program . rpc . requireKeysEqDefaultError ( {
accounts : {
someAccount ,
} ,
} ) ;
assert . fail (
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
) ;
} catch ( err ) {
assert . equal ( err . code , 2502 ) ;
}
} , [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:83. Error Code: RequireKeysEqViolated. Error Number: 2502. Error Message: A require_keys_eq expression was violated." ,
"Program log: Left:" ,
` Program log: ${ someAccount } ` ,
"Program log: Right:" ,
` Program log: ${ program . programId } ` ,
] ) ;
2021-11-18 07:42:07 -08:00
} ) ;
2021-01-15 23:05:26 -08:00
} ) ;