feat: add unstable API for dynamic program loading
This commit is contained in:
		@@ -5,4 +5,4 @@ export {Connection} from './connection';
 | 
				
			|||||||
export {PublicKey} from './publickey';
 | 
					export {PublicKey} from './publickey';
 | 
				
			||||||
export {SystemProgram} from './system-program';
 | 
					export {SystemProgram} from './system-program';
 | 
				
			||||||
export {Transaction} from './transaction';
 | 
					export {Transaction} from './transaction';
 | 
				
			||||||
export {Token} from './token-program';
 | 
					export {Token, TokenAmount} from './token-program';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,4 +105,35 @@ export class SystemProgram {
 | 
				
			|||||||
      userdata,
 | 
					      userdata,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Load a dynamic program.  Unstable API, will change
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @private
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static load(from: PublicKey, programId: PublicKey, name: string): Transaction {
 | 
				
			||||||
 | 
					    const userdataLayout = BufferLayout.struct([
 | 
				
			||||||
 | 
					      BufferLayout.u32('instruction'),
 | 
				
			||||||
 | 
					      Layout.publicKey('programId'),
 | 
				
			||||||
 | 
					      Layout.rustString('name'),
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let userdata = Buffer.alloc(1024);
 | 
				
			||||||
 | 
					    const encodeLength = userdataLayout.encode(
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        instruction: 3, // Load instruction
 | 
				
			||||||
 | 
					        programId: programId.toBuffer(),
 | 
				
			||||||
 | 
					        name,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      userdata,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    userdata = userdata.slice(0, encodeLength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return new Transaction({
 | 
				
			||||||
 | 
					      fee: 0,
 | 
				
			||||||
 | 
					      keys: [from],
 | 
				
			||||||
 | 
					      programId: SystemProgram.programId,
 | 
				
			||||||
 | 
					      userdata,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,12 @@
 | 
				
			|||||||
// @flow
 | 
					// @flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {Account} from '../src/account';
 | 
					import {
 | 
				
			||||||
import {Connection} from '../src/connection';
 | 
					  Account,
 | 
				
			||||||
import {SystemProgram} from '../src/system-program';
 | 
					  Connection,
 | 
				
			||||||
 | 
					  SystemProgram,
 | 
				
			||||||
 | 
					} from '../src';
 | 
				
			||||||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
 | 
					import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
 | 
				
			||||||
import {url} from './url.js';
 | 
					import {url} from './url';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!mockRpcEnabled) {
 | 
					if (!mockRpcEnabled) {
 | 
				
			||||||
  // The default of 5 seconds is too slow for live testing sometimes
 | 
					  // The default of 5 seconds is too slow for live testing sometimes
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								web3.js/test/new-account-with-tokens.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								web3.js/test/new-account-with-tokens.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					// @flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Account,
 | 
				
			||||||
 | 
					  Connection,
 | 
				
			||||||
 | 
					} from '../src';
 | 
				
			||||||
 | 
					import {mockRpc} from './__mocks__/node-fetch';
 | 
				
			||||||
 | 
					import {url} from './url';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function newAccountWithTokens(connection: Connection, amount: number = 10): Promise<Account> {
 | 
				
			||||||
 | 
					  const account = new Account();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mockRpc.push([
 | 
				
			||||||
 | 
					      url,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        method: 'requestAirdrop',
 | 
				
			||||||
 | 
					        params: [account.publicKey.toBase58(), amount],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        error: null,
 | 
				
			||||||
 | 
					        // Signature doesn't matter
 | 
				
			||||||
 | 
					        result: '3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await connection.requestAirdrop(account.publicKey, amount);
 | 
				
			||||||
 | 
					  return account;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,6 +1,15 @@
 | 
				
			|||||||
// @flow
 | 
					// @flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {Account, SystemProgram, BudgetProgram} from '../src';
 | 
					import {
 | 
				
			||||||
 | 
					  Account,
 | 
				
			||||||
 | 
					  BudgetProgram,
 | 
				
			||||||
 | 
					  Connection,
 | 
				
			||||||
 | 
					  SystemProgram,
 | 
				
			||||||
 | 
					  Transaction,
 | 
				
			||||||
 | 
					} from '../src';
 | 
				
			||||||
 | 
					import {mockRpcEnabled} from './__mocks__/node-fetch';
 | 
				
			||||||
 | 
					import {url} from './url';
 | 
				
			||||||
 | 
					import {newAccountWithTokens} from './new-account-with-tokens';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('createAccount', () => {
 | 
					test('createAccount', () => {
 | 
				
			||||||
  const from = new Account();
 | 
					  const from = new Account();
 | 
				
			||||||
@@ -52,4 +61,33 @@ test('assign', () => {
 | 
				
			|||||||
  // TODO: Validate transaction contents more
 | 
					  // TODO: Validate transaction contents more
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('unstable - load', async () => {
 | 
				
			||||||
 | 
					  if (mockRpcEnabled) {
 | 
				
			||||||
 | 
					    console.log('non-live test skipped');
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const connection = new Connection(url);
 | 
				
			||||||
 | 
					  const from = await newAccountWithTokens(connection);
 | 
				
			||||||
 | 
					  const noopProgramId = (new Account()).publicKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const loadTransaction = SystemProgram.load(
 | 
				
			||||||
 | 
					    from.publicKey,
 | 
				
			||||||
 | 
					    noopProgramId,
 | 
				
			||||||
 | 
					    'noop',
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let signature = await connection.sendTransaction(from, loadTransaction);
 | 
				
			||||||
 | 
					  expect(connection.confirmTransaction(signature)).resolves.toBe(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const noopTransaction = new Transaction({
 | 
				
			||||||
 | 
					    fee: 0,
 | 
				
			||||||
 | 
					    keys: [from.publicKey],
 | 
				
			||||||
 | 
					    programId: noopProgramId,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  signature = await connection.sendTransaction(from, noopTransaction);
 | 
				
			||||||
 | 
					  expect(connection.confirmTransaction(signature)).resolves.toBe(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,14 @@
 | 
				
			|||||||
// @flow
 | 
					// @flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {Account} from '../src/account';
 | 
					import {
 | 
				
			||||||
import {Connection} from '../src/connection';
 | 
					  Connection,
 | 
				
			||||||
import {Token, TokenAmount} from '../src/token-program';
 | 
					  PublicKey,
 | 
				
			||||||
import {PublicKey} from '../src/publickey';
 | 
					  Token,
 | 
				
			||||||
 | 
					  TokenAmount,
 | 
				
			||||||
 | 
					} from '../src';
 | 
				
			||||||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
 | 
					import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
 | 
				
			||||||
import {url} from './url.js';
 | 
					import {url} from './url';
 | 
				
			||||||
import type {SignatureStatus} from '../src/connection';
 | 
					import {newAccountWithTokens} from './new-account-with-tokens';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!mockRpcEnabled) {
 | 
					if (!mockRpcEnabled) {
 | 
				
			||||||
  // The default of 5 seconds is too slow for live testing sometimes
 | 
					  // The default of 5 seconds is too slow for live testing sometimes
 | 
				
			||||||
@@ -27,7 +29,7 @@ function mockGetLastId() {
 | 
				
			|||||||
  ]);
 | 
					  ]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function mockGetSignatureStatus(result: SignatureStatus = 'Confirmed') {
 | 
					function mockGetSignatureStatus(result: string = 'Confirmed') {
 | 
				
			||||||
  mockRpc.push([
 | 
					  mockRpc.push([
 | 
				
			||||||
    url,
 | 
					    url,
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -53,27 +55,6 @@ function mockSendTransaction() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function newAccountWithTokens(connection: Connection, amount: number = 10): Promise<Account> {
 | 
					 | 
				
			||||||
  const account = new Account();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    mockRpc.push([
 | 
					 | 
				
			||||||
      url,
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        method: 'requestAirdrop',
 | 
					 | 
				
			||||||
        params: [account.publicKey.toBase58(), amount],
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        error: null,
 | 
					 | 
				
			||||||
        result: '3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    ]);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  await connection.requestAirdrop(account.publicKey, amount);
 | 
					 | 
				
			||||||
  return account;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// A token created by the first test and used by all subsequent tests
 | 
					// A token created by the first test and used by all subsequent tests
 | 
				
			||||||
let testToken: Token;
 | 
					let testToken: Token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user