Skip to content

Commit

Permalink
Merge pull request #100 from kaleido-io/1.1-validation
Browse files Browse the repository at this point in the history
Add block number to tokens pools/custom contract listeners + better 1.1 support
  • Loading branch information
dechdev authored Aug 25, 2022
2 parents 0b57d3c + 9a97abd commit 5a7d32f
Show file tree
Hide file tree
Showing 16 changed files with 270 additions and 51 deletions.
34 changes: 21 additions & 13 deletions server/src/controllers/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Get, JsonController, Param, QueryParam } from 'routing-controllers';
import { Get, InternalServerError, JsonController, Param, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { firefly } from '../clients/firefly';
import { FFStatus, Organization, Plugin, Plugins, Transaction, Verifier } from '../interfaces';
Expand Down Expand Up @@ -33,19 +33,27 @@ export class CommonController {
@ResponseSchema(Verifier, { isArray: true })
@OpenAPI({ summary: 'List verifiers (such as Ethereum keys) for all organizations in network' })
async verifiers(): Promise<Verifier[]> {
const orgs = await firefly.getOrganizations();
const defaultVerifiers = await firefly.getVerifiers('default');
const legacyVerifiers = await firefly.getVerifiers('ff_system');
const verifiers = defaultVerifiers.concat(legacyVerifiers);

const result: Verifier[] = [];
for (const v of verifiers) {
const o = orgs.find((o) => o.id === v.identity);
if (o !== undefined) {
result.push({ did: o.did, type: v.type, value: v.value });
try {
const orgs = await firefly.getOrganizations();
let verifiers = await firefly.getVerifiers('default');
if (verifiers.length === 0) {
// attempt to query legacy ff_system verifiers
verifiers = await firefly.getVerifiers('ff_system');
}
const result: Verifier[] = [];
for (const v of verifiers) {
const o = orgs.find((o) => o.id === v.identity);
if (o !== undefined) {
result.push({ did: o.did, type: v.type, value: v.value });
}
}
return result;
} catch (err) {
if (err.message == "FF10187: Namespace does not exist") {
return [];
}
throw new InternalServerError(err.message);
}
return result;
}

@Get('/verifiers/self')
Expand Down Expand Up @@ -92,7 +100,7 @@ export class CommonController {
const status = await firefly.getStatus();
if ("multiparty" in status) {
return {
multiparty: status.multiparty.enabled,
multiparty: status.multiparty?.enabled,
};
} else {
// Assume multiparty mode if `multiparty` key is missing from status
Expand Down
6 changes: 6 additions & 0 deletions server/src/controllers/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ export class ContractsController {
const listener = await firefly.createContractAPIListener(body.apiName, body.eventPath, {
topic: body.topic,
name: body.name,
options: {
firstEvent: body.firstEvent
}
});
return {
id: listener.id,
Expand Down Expand Up @@ -214,6 +217,9 @@ export class ContractsTemplateController {
{
topic: <%= ${q('topic')} %>,<% if (name) { %>
<% print('name: ' + ${q('name')} + ',') } %>
options: {<% if (firstEvent) { %>
<% print('firstEvent: ' + ${q('firstEvent')} + ',') } %>
}
},
);
return {
Expand Down
2 changes: 2 additions & 0 deletions server/src/controllers/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export class TokensController {
type: body.type,
config: {
address: body.address,
blockNumber: body.blockNumber,
},
});
return { type: 'token_pool', id: pool.id };
Expand Down Expand Up @@ -259,6 +260,7 @@ export class TokensTemplateController {
type: <%= ${q('type')} %>,
config: {<% if (address) { %>
<% print('address: ' + ${q('address')} + ',') } %>
blockNumber: <%= ${q('blockNumber')} %>,
}
});
return { type: 'token_pool', id: pool.id };
Expand Down
13 changes: 13 additions & 0 deletions server/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export class DatatypeDefinition {
version: string;
}

export class FFContractListenerOptions {
@IsOptional()
firstEvent: string;
}

export class BroadcastValue extends BaseMessageFields {
@IsString()
@IsOptional()
Expand Down Expand Up @@ -144,6 +149,10 @@ export class TokenPoolInput {
@IsString()
@IsOptional()
address?: string;

@IsString()
@IsOptional()
blockNumber?: string;
}

export class TokenPool extends TokenPoolInput {
Expand Down Expand Up @@ -305,6 +314,10 @@ export class ContractListener {

@IsString()
eventPath: string;

@IsOptional()
@IsString()
firstEvent?: string;
}

export class ContractListenerLookup {
Expand Down
4 changes: 0 additions & 4 deletions server/test/common.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ describe('Common Operations', () => {

mockFireFly.getOrganizations.mockResolvedValueOnce(orgs);
mockFireFly.getVerifiers.mockResolvedValueOnce(verifiers);
mockFireFly.getVerifiers.mockResolvedValueOnce([]);

await request(server)
.get('/api/common/verifiers')
Expand All @@ -71,8 +70,5 @@ describe('Common Operations', () => {

expect(mockFireFly.getOrganizations).toHaveBeenCalledWith();
expect(mockFireFly.getVerifiers).toHaveBeenCalledWith('default');

expect(mockFireFly.getOrganizations).toHaveBeenCalledWith();
expect(mockFireFly.getVerifiers).toHaveBeenCalledWith('ff_system');
});
});
4 changes: 4 additions & 0 deletions server/test/contracts.template.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ describe('Templates: Smart Contracts', () => {
topic: 'app1',
apiName: 'api1',
eventPath: 'set',
firstEvent: 'newest',
}),
).toBe(
formatTemplate(`
Expand All @@ -135,6 +136,9 @@ describe('Templates: Smart Contracts', () => {
'set',
{
topic: 'app1',
options: {
firstEvent: 'newest',
}
},
);
return {
Expand Down
4 changes: 4 additions & 0 deletions server/test/contracts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ describe('Smart Contracts', () => {
apiName: 'my-api',
eventPath: 'Changed',
topic: 'my-app',
firstEvent: 'newest'
};
const listener = {
id: 'listener1',
Expand All @@ -245,6 +246,9 @@ describe('Smart Contracts', () => {

expect(mockFireFly.createContractAPIListener).toHaveBeenCalledWith('my-api', 'Changed', {
topic: 'my-app',
options: {
firstEvent: 'newest',
},
});
});
});
2 changes: 2 additions & 0 deletions server/test/tokens.template.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ describe('Templates: Tokens', () => {
symbol: 'P1',
type: 'fungible',
address: undefined,
blockNumber: '0',
}),
).toBe(
formatTemplate(`
Expand All @@ -24,6 +25,7 @@ describe('Templates: Tokens', () => {
symbol: 'P1',
type: 'fungible',
config: {
blockNumber: '0',
}
});
return { type: 'token_pool', id: pool.id };
Expand Down
14 changes: 13 additions & 1 deletion ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import {
SnackbarMessageType,
} from './components/Snackbar/MessageSnackbar';
import { SDK_PATHS } from './constants/SDK_PATHS';
import {
GatewayTutorialSections,
TutorialSections,
} from './constants/TutorialSections';
import { ApplicationContext } from './contexts/ApplicationContext';
import { SnackbarContext } from './contexts/SnackbarContext';
import {
Expand All @@ -19,13 +23,14 @@ import {
ISelfIdentity,
IVerifier,
} from './interfaces/api';
import { ITutorialSection } from './interfaces/tutorialSection';
import { themeOptions } from './theme';
import { fetchCatcher, summarizeFetchError } from './utils/fetches';

export const MAX_FORM_ROWS = 10;

function App() {
const [initialized, setInitialized] = useState(true);
const [initialized, setInitialized] = useState(false);
const [message, setMessage] = useState('');
const [messageType, setMessageType] = useState<SnackbarMessageType>('error');

Expand All @@ -41,6 +46,9 @@ function App() {
});
const [tokensDisabled, setTokensDisabled] = useState(false);
const [blockchainPlugin, setBlockchainPlugin] = useState('');
const [tutorialSections, setTutorialSections] = useState<ITutorialSection[]>(
[]
);

useEffect(() => {
Promise.all([
Expand All @@ -59,6 +67,7 @@ function App() {
const ffStatus = statusResponse as IFireflyStatus;
setMultiparty(ffStatus.multiparty);
if (ffStatus.multiparty === true) {
setTutorialSections(TutorialSections);
fetchCatcher(SDK_PATHS.verifiers)
.then((verifierRes: IVerifier[]) => {
setSelfIdentity({
Expand All @@ -71,6 +80,8 @@ function App() {
.catch((err) => {
reportFetchError(err);
});
} else {
setTutorialSections(GatewayTutorialSections);
}
})
.finally(() => {
Expand Down Expand Up @@ -110,6 +121,7 @@ function App() {
tokensDisabled,
blockchainPlugin,
multiparty,
tutorialSections,
}}
>
<StyledEngineProvider injectFirst>
Expand Down
29 changes: 22 additions & 7 deletions ui/src/AppWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,17 @@ export const DEFAULT_ACTION = [
TUTORIAL_FORMS.BROADCAST,
];

export const DEFAULT_GATEWAY_ACTION = [
TUTORIAL_CATEGORIES.TOKENS,
TUTORIAL_FORMS.POOL,
];

export const AppWrapper: React.FC = () => {
const { pathname, search } = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
const { t } = useTranslation();
const { setPayloadMissingFields } = useContext(ApplicationContext);
const { setPayloadMissingFields, multiparty, tutorialSections } =
useContext(ApplicationContext);
const [action, setAction] = useState<string | null>(null);
const [categoryID, setCategoryID] = useState<string | undefined>(undefined);
const [formID, setFormID] = useState<string | undefined>(undefined);
Expand All @@ -64,7 +70,7 @@ export const AppWrapper: React.FC = () => {

useEffect(() => {
initializeFocusedForm();
}, [pathname, search]);
}, [pathname, search, tutorialSections]);

// Set form object based on action
useEffect(() => {
Expand All @@ -84,11 +90,16 @@ export const AppWrapper: React.FC = () => {

const initializeFocusedForm = () => {
const existingAction = searchParams.get(ACTION_QUERY_KEY);

if (existingAction === null) {
setCategoryID(DEFAULT_ACTION[0]);
setFormID(DEFAULT_ACTION[1]);
setActionParam(DEFAULT_ACTION[0], DEFAULT_ACTION[1]);
if (multiparty) {
setCategoryID(DEFAULT_ACTION[0]);
setFormID(DEFAULT_ACTION[1]);
setActionParam(DEFAULT_ACTION[0], DEFAULT_ACTION[1]);
} else {
setCategoryID(DEFAULT_GATEWAY_ACTION[0]);
setFormID(DEFAULT_GATEWAY_ACTION[1]);
setActionParam(DEFAULT_GATEWAY_ACTION[0], DEFAULT_GATEWAY_ACTION[1]);
}
} else {
const validAction: string[] = getValidAction(existingAction);
setCategoryID(validAction[0]);
Expand Down Expand Up @@ -134,7 +145,11 @@ export const AppWrapper: React.FC = () => {

const getValidAction = (action: string) => {
if (!isValidAction(action)) {
return DEFAULT_ACTION;
if (multiparty) {
return DEFAULT_ACTION;
} else {
return DEFAULT_GATEWAY_ACTION;
}
}

return action.split(ACTION_DELIM);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const RegisterContractApiListenerForm: React.FC = () => {
const [contractApi, setContractApi] = useState<string>('');
const [events, setEvents] = useState<string[]>([]);
const [eventPath, setEventPath] = useState<string>('');
const [firstEvent, setFirstEvent] = useState('newest');

const [name, setName] = useState<string>('');
const [topic, setTopic] = useState<string>('');
Expand All @@ -52,8 +53,9 @@ export const RegisterContractApiListenerForm: React.FC = () => {
topic,
apiName: contractApi,
eventPath,
firstEvent,
});
}, [name, topic, contractApi, eventPath, formID]);
}, [name, topic, contractApi, eventPath, formID, firstEvent]);

useEffect(() => {
isMounted &&
Expand Down Expand Up @@ -157,6 +159,17 @@ export const RegisterContractApiListenerForm: React.FC = () => {
/>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl fullWidth required>
<TextField
fullWidth
label={t('firstEvent')}
onChange={(e) => setFirstEvent(e.target.value)}
helperText={t('firstEventDescription')}
value={firstEvent}
/>
</FormControl>
</Grid>
</Grid>
</Grid>
);
Expand Down
Loading

0 comments on commit 5a7d32f

Please sign in to comment.