Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blob #71

Merged
merged 10 commits into from
Jul 28, 2023
9 changes: 2 additions & 7 deletions src/api/v1/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AnyAction,
Asset,
Authority,
Blob,
BlockId,
BlockTimestamp,
Bytes,
Expand Down Expand Up @@ -124,13 +125,7 @@ export class GetRawAbiResponse extends Struct {
@Struct.field('name') declare account_name: Name
@Struct.field('checksum256') declare code_hash: Checksum256
@Struct.field('checksum256') declare abi_hash: Checksum256
@Struct.field('string') declare abi: ABI
static from(data: any) {
return super.from({
...data,
abi: Serializer.decode({data: Bytes.from(Buffer.from(data.abi, 'base64')), type: ABI}),
})
}
@Struct.field(Blob) declare abi: Blob
}

@Struct.type('account_object')
Expand Down
12 changes: 9 additions & 3 deletions src/chain/abi.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {isInstanceOf} from '../utils'
import type {ABISerializableObject} from '../serializer/serializable'
import type {ABIDecoder} from '../serializer/decoder'
import {abiDecode, ABIDecoder} from '../serializer/decoder'
import {abiEncode, ABIEncoder} from '../serializer/encoder'

import {Name, NameType} from '../'
import {Blob, Name, NameType} from '../'

export type ABIDef = string | Partial<ABI.Def> | ABI
export type ABIDef = string | Partial<ABI.Def> | ABI | Blob

export class ABI implements ABISerializableObject {
static abiName = 'abi'
Expand Down Expand Up @@ -39,6 +39,12 @@ export class ABI implements ABISerializableObject {
if (isInstanceOf(value, ABI)) {
return value
}
if (isInstanceOf(value, Blob)) {
return abiDecode({
data: value.array,
type: this,
})
}
if (typeof value === 'string') {
return new ABI(JSON.parse(value))
}
Expand Down
58 changes: 58 additions & 0 deletions src/chain/blob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {ABISerializableObject} from '../serializer/serializable'
import {ABIEncoder} from '../serializer/encoder'
import {arrayEquals, isInstanceOf} from '../utils'

export type BlobType = Blob | string

export class Blob implements ABISerializableObject {
static abiName = 'blob'

/**
* Create a new Bytes instance.
* @note Make sure to take a [[copy]] before mutating the bytes as the underlying source is not copied here.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Docstring says Bytes and references non existent method

Copy link
Member Author

Choose a reason for hiding this comment

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

Bytes is where I copied the class structure from instead of writing it from scratch... my sloppy copy/pasta. Whoops 😅

*/
static from(value: BlobType): Blob {
if (isInstanceOf(value, this)) {
return value
}
if (typeof value === 'string') {
return this.fromString(value)
}
throw new Error('Invalid blob')
}

static fromString(value: string) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This needs to handle the invalid base64 padding nodeos outputs

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I have tests ensuring the invalid stuff works here: 1cd6b9b

return new this(new Uint8Array(Buffer.from(value, 'base64')))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Didn't catch this first time around but you cannot use Buffer in core, it's not available outside of node.js. You'll have to use atob and btoa (see https://developer.mozilla.org/en-US/docs/Glossary/Base64)

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. I originally swapped to a buffer because VSCode was complaining atob was deprecated 😅

New snag... atob and btoa aren't available in nodejs 14, so our tests against that version are failing. I added back some checks to see if Buffer exists, and if so, use it.

a8526b7

}

readonly array: Uint8Array

constructor(array: Uint8Array) {
this.array = array
}

equals(other: BlobType): boolean {
const self = this.constructor as typeof Blob
try {
return arrayEquals(this.array, self.from(other).array)
} catch {
return false
}
}

get base64String(): string {
return Buffer.from(this.array).toString('base64')
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, no Buffer

}

toABI(encoder: ABIEncoder) {
encoder.writeArray(this.array)
}

toString() {
return this.base64String
}

toJSON() {
return this.toString()
}
}
1 change: 1 addition & 0 deletions src/chain/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// types with no inter-dependencies
export * from './blob'
export * from './bytes'
export * from './checksum'
export * from './key-type'
Expand Down
7 changes: 5 additions & 2 deletions test/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
APIClient,
APIError,
Asset,
Blob,
BlockId,
Bytes,
Checksum256,
Expand Down Expand Up @@ -82,8 +83,10 @@ suite('api v1', function () {
'd84356074da34a976528321472d73ac919227b9b01d9de59d8ade6d96440455c'
)
)
assert.instanceOf(response.abi, ABI)
assert.equal(response.abi.version, 'eosio::abi/1.2')
assert.instanceOf(response.abi, Blob)
const abi = ABI.from(response.abi)
assert.instanceOf(abi, ABI)
assert.equal(abi.version, 'eosio::abi/1.2')
})

test('chain get_account', async function () {
Expand Down
24 changes: 23 additions & 1 deletion test/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AnyTransaction,
Asset,
Authority,
Blob,
BlockId,
BlockTimestamp,
Bytes,
Expand All @@ -15,7 +16,6 @@ import {
Int32,
Int64,
Name,
P2P,
PermissionLevel,
PublicKey,
Signature,
Expand Down Expand Up @@ -115,6 +115,28 @@ suite('chain', function () {
assert.equal(blockId2.blockNum.equals(7), true)
})

test('blob', function () {
const expected = Bytes.from([0xbe, 0xef, 0xfa, 0xce])

// Correct
const string = 'vu/6zg=='
const blob = Blob.from(string)
assert.isTrue(Bytes.from(blob.array).equals(expected))

// Wrong padding, ensure it still works
const string2 = 'vu/6zg='
const blob2 = Blob.from(string2)
assert.isTrue(Bytes.from(blob2.array).equals(expected))

const string3 = 'vu/6zg'
const blob3 = Blob.from(string3)
assert.isTrue(Bytes.from(blob3.array).equals(expected))

const string4 = 'vu/6zg==='
const blob4 = Blob.from(string4)
assert.isTrue(Bytes.from(blob4.array).equals(expected))
})

test('bytes', function () {
assert.equal(Bytes.from('hello', 'utf8').toString('hex'), '68656c6c6f')
assert.equal(Bytes.equal('beef', 'beef'), true)
Expand Down
Loading