Skip to content

Commit

Permalink
Test/basic elements (#570)
Browse files Browse the repository at this point in the history
* test storage

* complete address test

* complete internal test

* test key file

* Improve key address generation test
  • Loading branch information
Ben-Rey authored Apr 24, 2024
1 parent a4ad4c5 commit d0c4452
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 8 deletions.
4 changes: 2 additions & 2 deletions packages/massa-web3/src/experimental/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class Account {
} as AccountV1KeyStore
}
default:
throw new Error(`Unsupported version`)
throw new Error(`unsupported version`)
}
}

Expand Down Expand Up @@ -214,7 +214,7 @@ export class Account {
return new Account(privateKey, publicKey, address, keystore.Version)
}
default:
throw new Error(`Unsupported version`)
throw new Error(`unsupported version`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class Address {
case Version.V0:
return new Address(new Base58(), new VarintVersioner(), version, false)
default:
throw new Error(`Unsupported version: ${version}`)
throw new Error(`unsupported version: ${version}`)
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/massa-web3/src/experimental/basicElements/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export class PublicKey {
publicKey.version
)
} catch (e) {
throw new Error(`Invalid public key string: ${e.message}`)
throw new Error(`invalid public key string: ${e.message}`)
}

return publicKey
Expand Down
58 changes: 54 additions & 4 deletions packages/massa-web3/test/experimental/unit/address.spec.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,73 @@
import { Account } from '../../../src/experimental/account'
import { Address } from '../../../src/experimental/basicElements'
import { Version } from '../../../src/experimental/crypto/interfaces/versioner'
import { Address as LegacyAddress } from '../../../src/utils/keyAndAddresses'

const contractAddress = 'AS1eK3SEXGDAWN6pZhdr4Q7WJv6UHss55EB14hPy4XqBpiktfPu6'
const invalidVersion = -1 as Version

describe('Address tests', () => {
let account: Account

beforeAll(async () => {
account = await Account.generate()
})

test('Serialization', async () => {
test('serialization and deserialization', async () => {
const addStr = account.address.toString()
const address = Address.fromString(addStr)
const ref = new LegacyAddress(addStr)
const legacyAddress = new LegacyAddress(addStr)
const bytes = address.toBytes()

// serialization
expect(bytes).toStrictEqual(Uint8Array.from(ref.toBytes()))
expect(bytes).toStrictEqual(Uint8Array.from(legacyAddress.toBytes()))

// deserialization
expect(Address.fromBytes(bytes)).toStrictEqual(Address.fromString(addStr))
expect(Address.fromBytes(bytes)).toStrictEqual(address)
})

test('fromString throws error for invalid address string', () => {
expect(() => Address.fromString('invalid_address_string')).toThrow(
/invalid address string:/
)
})

test('fromString throws error for invalid version', () => {
expect(() =>
Address.fromString(account.address.toString(), invalidVersion)
).toThrow(/unsupported version:/)
})

test('toString returns string with user prefix for EOA', () => {
const address = Address.fromPublicKey(account.publicKey)
expect(address.toString()).toMatch(/^AU/)
})

test('toString returns string with contract prefix for contract account', () => {
const address = Address.fromString(contractAddress)
expect(address.toString()).toMatch(/^AS/)
})

test('toBytes returns bytes with EOA prefix for EOA', () => {
const address = Address.fromPublicKey(account.publicKey)
const bytes = address.toBytes()

// The first byte should be 0 for EOA
expect(bytes[0]).toBe(0)
})

test('toBytes returns bytes with contract prefix for contract account', () => {
const address = Address.fromString(contractAddress)
const bytes = address.toBytes()
// The first byte should be 1 for contract account
expect(bytes[0]).toBe(1)
})

test('getByteLength returns correct length', () => {
const address = Address.fromPublicKey(account.publicKey)
const bytes = address.toBytes()
const byteLength = Address.getByteLength(bytes)

expect(byteLength).toBe(bytes.length)
})
})
35 changes: 35 additions & 0 deletions packages/massa-web3/test/experimental/unit/internal.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
extractData,
checkPrefix,
} from '../../../src/experimental/basicElements/internal'
import Base58 from '../../../src/experimental/crypto/base58'
import VarintVersioner from '../../../src/experimental/crypto/varintVersioner'
import { Version } from '../../../src/experimental/crypto/interfaces/versioner'

describe('Internal functions tests', () => {
const serializer = new Base58()
const versioner = new VarintVersioner()

test('extractData throws error for invalid version', () => {
const data = serializer.serialize(Uint8Array.from([0, 1, 2, 3, 4]))
expect(() => extractData(serializer, versioner, data, Version.V1)).toThrow(
'invalid version: 0. 1 was expected.'
)
})

test('extractData returns correct data for valid version', () => {
const data = serializer.serialize(Uint8Array.from([0, 1, 2, 3, 4]))
const extractedData = extractData(serializer, versioner, data, Version.V0)
expect(extractedData).toEqual(Uint8Array.from([1, 2, 3, 4]))
})

test('checkPrefix throws error for invalid prefix', () => {
expect(() => checkPrefix('IP_invalid_prefix', 'AS')).toThrow(
'invalid prefix: IP. AS was expected.'
)

expect(() => checkPrefix('IP_invalid_prefix', 'AS', 'AU')).toThrow(
'invalid prefix: IP. one of AS or AU was expected.'
)
})
})
125 changes: 125 additions & 0 deletions packages/massa-web3/test/experimental/unit/key.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Address } from '../../../src/experimental/basicElements/address'
import {
PrivateKey,
PublicKey,
} from '../../../src/experimental/basicElements/keys'
import { Version } from '../../../src/experimental/crypto/interfaces/versioner'
import { SecretKey as LegacyPrivateKey } from '../../../src/utils/keyAndAddresses'
import { Address as LegacyAddress } from '../../../src/utils/keyAndAddresses'

const invalidVersion = -1 as Version

describe('PrivateKey and PublicKey tests', () => {
let privateKey: PrivateKey
let publicKey: PublicKey

beforeAll(async () => {
privateKey = PrivateKey.generate()
publicKey = await PublicKey.fromPrivateKey(privateKey)
})

describe('Conversion to and from Bytes', () => {
test('PublicKey toBytes and fromBytes', async () => {
const publicKey = await PublicKey.fromPrivateKey(privateKey)
const newPubKeyBytes = PublicKey.fromBytes(publicKey.bytes)
expect(newPubKeyBytes.bytes).toEqual(publicKey.bytes)
})

test('PrivateKey toBytes and fromBytes', async () => {
const privateKey = PrivateKey.generate()
const newPKeyBytes = PrivateKey.fromBytes(privateKey.bytes)
expect(newPKeyBytes.bytes).toEqual(privateKey.bytes)
})
})

describe('Address Generation', () => {
test('PublicKey getAddress', async () => {
// Generate address from Legacy keys objects
const legacyPrivKey = new LegacyPrivateKey(
'S1eK3SEXGDAWN6pZhdr4Q7WJv6UHss55EB14hPy4XqBpiktfPu6'
)
const legacyPubKey = await legacyPrivKey.getPublicKey()
const legacyAddress = LegacyAddress.fromPublicKey(legacyPubKey)

// Generate address from new keys objects
const privKey = PrivateKey.fromString(
'S1eK3SEXGDAWN6pZhdr4Q7WJv6UHss55EB14hPy4XqBpiktfPu6'
)
const pubKey = await PublicKey.fromPrivateKey(privKey)
const address = Address.fromPublicKey(pubKey)

// Verify that the addresses are the same
expect(address.toString()).toBe(legacyAddress.base58Encoded)
})
})

describe('Signing and Verification', () => {
test('PrivateKey sign and PublicKey verify', async () => {
const message = new TextEncoder().encode('Hello, world!')
const signature = await privateKey.sign(message)
const isValid = await publicKey.verify(message, signature)

expect(isValid).toBe(true)
})
})

describe('From String', () => {
test('fromString returns PrivateKey when valid private key string', () => {
const privateKeyString = privateKey.toString()
const key = PrivateKey.fromString(privateKeyString)
expect(key).toBeInstanceOf(PrivateKey)
expect(key.toString()).toBe(privateKey.toString())
})

test('fromString returns PublicKey when valid public key string', () => {
const publicKeyString = publicKey.toString()
const key = PublicKey.fromString(publicKeyString)
expect(key).toBeInstanceOf(PublicKey)
expect(key.toString()).toBe(publicKey.toString())
})

test('fromString throws error for invalid private key string', () => {
const invalidPrivateKeyString = 'invalidPrivateKey'
expect(() => PrivateKey.fromString(invalidPrivateKeyString)).toThrow(
/invalid private key string/
)
})

test('fromString throws error for invalid public key string', () => {
const invalidPublicKeyString = 'invalidPublicKey'

expect(() =>
PublicKey.fromString(invalidPublicKeyString, Version.V0)
).toThrow(/invalid public key string/)
})

test('fromString throws error for invalid public key version', () => {
const publicKeyString = publicKey.toString()
expect(() =>
PublicKey.fromString(publicKeyString, invalidVersion)
).toThrow(/unsupported version/)
})
test('fromString throws error for invalid private key version', () => {
const privateKeyString = privateKey.toString()

expect(() =>
PrivateKey.fromString(privateKeyString, invalidVersion)
).toThrow(/unsupported version/)
})
})

describe('From Environment Variables', () => {
test('fromEnv returns PrivateKey when PRIVATE_KEY environment variable set', () => {
process.env.PRIVATE_KEY = privateKey.toString()
const key = PrivateKey.fromEnv()
expect(key.toString()).toBe(privateKey.toString())
})

test('fromEnv throws error when PRIVATE_KEY environment variable is not set', () => {
delete process.env.PRIVATE_KEY
expect(() => PrivateKey.fromEnv()).toThrow(
'missing `PRIVATE_KEY` environment variable'
)
})
})
})
37 changes: 37 additions & 0 deletions packages/massa-web3/test/experimental/unit/storage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { StorageCost } from '../../../src/experimental/basicElements/storage'
import {
BASE_ACCOUNT_CREATION_COST,
STORAGE_BYTE_COST,
} from '@massalabs/web3-utils'

describe('StorageCost', () => {
describe('bytes', () => {
it('should calculate the cost of a given number of bytes', () => {
const numberOfBytes = 10
const expectedCost = BigInt(numberOfBytes) * STORAGE_BYTE_COST
expect(StorageCost.bytes(numberOfBytes)).toEqual(expectedCost)
})
})

describe('account', () => {
it('should calculate the cost of creating a new account', () => {
expect(StorageCost.account()).toEqual(BASE_ACCOUNT_CREATION_COST)
})
})

describe('smartContract', () => {
it('should calculate the cost of deploying a smart contract', () => {
const numberOfBytes = 10
const expectedCost =
StorageCost.bytes(numberOfBytes) + StorageCost.account()
expect(StorageCost.smartContract(numberOfBytes)).toEqual(expectedCost)
})
})

describe('newEntry', () => {
it('should calculate the cost of creating a new entry in the datastore', () => {
const expectedCost = StorageCost.bytes(4)
expect(StorageCost.newEntry()).toEqual(expectedCost)
})
})
})

1 comment on commit d0c4452

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report for experimental massa-web3

St.
Category Percentage Covered / Total
🔴 Statements 43.31% 615/1420
🔴 Branches 18.33% 68/371
🔴 Functions 34.74% 99/285
🔴 Lines 43.1% 603/1399

Test suite run success

36 tests passing in 7 suites.

Report generated by 🧪jest coverage report action from d0c4452

Please sign in to comment.