Skip to content

Commit 95a9c36

Browse files
Merge remote-tracking branch 'origin/dev' into feat/chromatic-story-modes
2 parents 5c06e0d + 92f3662 commit 95a9c36

File tree

25 files changed

+836
-271
lines changed

25 files changed

+836
-271
lines changed

.github/workflows/stale.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ jobs:
1919
stale-pr-message: "This issue is stale because it has been open 30 days with no activity."
2020
days-before-stale: 30
2121
days-before-close: -1
22+
operations-per-run: 250

.storybook/ChakraDecorator.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {
2+
ChakraBaseProvider,
3+
extendBaseTheme,
4+
useColorMode,
5+
} from "@chakra-ui/react"
6+
import type { Decorator } from "@storybook/react"
7+
8+
import theme from "../src/@chakra-ui/theme"
9+
import { useEffect, useMemo, useState } from "react"
10+
import i18n from "./i18next"
11+
12+
type DecoratorProps = Parameters<Decorator>
13+
14+
const ColorModeSync = ({ context }: { context: DecoratorProps[1] }) => {
15+
const { setColorMode } = useColorMode()
16+
17+
useEffect(() => {
18+
const isDarkMode = localStorage.getItem("chakra-ui-color-mode") === "dark"
19+
20+
context.globals.colorMode = isDarkMode ? "dark" : "light"
21+
}, [])
22+
23+
useEffect(() => {
24+
setColorMode(context.globals.colorMode)
25+
}, [setColorMode, context])
26+
27+
return null
28+
}
29+
30+
/**
31+
* This is a custom local setup of the official Chakra UI Storybook addon.
32+
*
33+
* A local version was created in response to provide a better sync between
34+
* updated local direction to the Chakra theme.
35+
*
36+
* (This would most likely not be updated in the addon due to ongoing creation of Chakra v3 at the time this
37+
* setup was created.)
38+
*
39+
* Will be deprecated and removed when Chakra v3 is available for migration.
40+
*
41+
*/
42+
export const ChakraDecorator: Decorator = (getStory, context) => {
43+
const [dir, updateDir] = useState<"ltr" | "rtl">()
44+
45+
i18n.on("languageChanged", (locale) => {
46+
const direction = i18n.dir(locale)
47+
document.documentElement.dir = direction
48+
updateDir(direction)
49+
})
50+
51+
const themeWithDirectionOverride = useMemo(() => {
52+
return extendBaseTheme({ direction: dir }, theme)
53+
}, [dir])
54+
55+
return (
56+
<ChakraBaseProvider theme={themeWithDirectionOverride}>
57+
<>
58+
<ColorModeSync context={context} />
59+
{getStory(context)}
60+
</>
61+
</ChakraBaseProvider>
62+
)
63+
}

.storybook/i18next.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const baseLocales = {
66
zh: { title: "中国人", left: "Zh" },
77
ru: { title: "Русский", left: "Ru" },
88
uk: { title: "українська", left: "Uk" },
9+
fa: { title: "فارسی", left: "Fa" },
910
}
1011

1112
// Only i18n files named in this array are being exposed to Storybook. Add filenames as necessary.

.storybook/main.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const config: StorybookConfig = {
2121
"@storybook/addon-links",
2222
"@storybook/addon-essentials",
2323
"@storybook/addon-interactions",
24-
"@chakra-ui/storybook-addon",
2524
"storybook-react-i18next",
2625
],
2726
staticDirs: ["../public"],

.storybook/preview.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,36 @@
1-
import { extendBaseTheme } from "@chakra-ui/react"
21
import type { Preview } from "@storybook/react"
32

43
import theme from "../src/@chakra-ui/theme"
54

5+
import { ChakraDecorator } from "./ChakraDecorator"
66
import i18n, { baseLocales } from "./i18next"
77

88
import "../src/styles/global.css"
99

10-
const extendedTheme = extendBaseTheme(theme)
11-
12-
export const chakraBreakpointArray = Object.entries(
13-
extendedTheme.breakpoints
14-
) as [string, string][]
10+
export const chakraBreakpointArray = Object.entries(theme.breakpoints) as [
11+
string,
12+
string
13+
][]
1514

1615
const preview: Preview = {
1716
globals: {
1817
locale: "en",
1918
locales: baseLocales,
2019
},
20+
globalTypes: {
21+
colorMode: {
22+
name: "Color Mode",
23+
description: "Change the color mode",
24+
toolbar: {
25+
icon: "circlehollow",
26+
items: [
27+
{ value: "light", icon: "circlehollow", title: "Light Mode" },
28+
{ value: "dark", icon: "circle", title: "Dark Mode" },
29+
],
30+
},
31+
},
32+
},
33+
decorators: [ChakraDecorator],
2134
parameters: {
2235
i18n,
2336
actions: { argTypesRegex: "^on[A-Z].*" },
@@ -35,9 +48,6 @@ const preview: Preview = {
3548
order: ["Atoms", "Molecules", "Organisms", "Templates", "Pages"],
3649
},
3750
},
38-
chakra: {
39-
theme: extendedTheme,
40-
},
4151
layout: "centered",
4252
// Modify viewport selection to match Chakra breakpoints (or custom breakpoints)
4353
viewport: {

.storybook/types.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import type { ArgTypes } from "@storybook/react"
2+
import type { ThemingProps } from "@chakra-ui/react"
3+
4+
// Type declarations below pulled directly from `@chakra-ui/storybook-addon`
5+
// with some alteration
6+
// (Subject to deprecation and removal upon release of Chakra v3)
7+
8+
/**
9+
* `keyof` alternative which omits non-string keys
10+
*/
11+
type KeyOf<T> = [T] extends [never]
12+
? never
13+
: T extends object
14+
? Extract<keyof T, string>
15+
: never
16+
17+
export type ThemingArgTypeKey = "variant" | "size"
18+
19+
/**
20+
* Create Storybook controls based on a Chakra UI theme component.
21+
*
22+
* @example
23+
* export default {
24+
* title: "Components / Forms / Button",
25+
* argTypes: getThemingArgTypes(theme, "Button"),
26+
* }
27+
*
28+
* @example full example
29+
* import { Meta, StoryFn } from "@storybook/react"
30+
* import { getThemingArgTypes } from "@chakra-ui/storybook-addon"
31+
* import { theme } from "<your-theme>"
32+
*
33+
* export default {
34+
* title: "Components / Forms / Button",
35+
* argTypes: {
36+
* ...getThemingArgTypes(theme, "Button"),
37+
* children: "string"
38+
* },
39+
* args: { children: "Button" },
40+
* } as Meta
41+
*
42+
* interface StoryProps extends ThemingProps<"Button"> {
43+
* children?: React.ReactNode
44+
* }
45+
*
46+
* export const Basic: StoryFn<StoryProps> = (props) => <Button {...props} />
47+
*
48+
* @param theme same Chakra UI theme used in .storybook/preview.tsx
49+
* @param componentName component name to create the ArgTypes for
50+
*/
51+
export function getThemingArgTypes<
52+
Theme extends Record<string, any>,
53+
ComponentName extends KeyOf<Theme["components"]>
54+
>(theme: Theme, componentName: ComponentName) {
55+
const component = theme.components[componentName]
56+
if (!component) {
57+
return undefined
58+
}
59+
60+
const argTypes: ArgTypes<
61+
Partial<Pick<ThemingProps<ComponentName>, ThemingArgTypeKey>>
62+
> = {}
63+
64+
const variantOptions = Object.keys(component.variants || {})
65+
if (variantOptions.length) {
66+
argTypes.variant = {
67+
type: { name: "enum", value: variantOptions },
68+
defaultValue: component.defaultProps?.variant,
69+
}
70+
}
71+
72+
const sizeOptions = Object.keys(component.sizes || {})
73+
if (sizeOptions.length) {
74+
argTypes.size = {
75+
type: { name: "enum", value: sizeOptions },
76+
defaultValue: component.defaultProps?.size,
77+
}
78+
}
79+
80+
return argTypes
81+
}

netlify.toml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,21 @@
3939
path = "en/developers/tutorials/creating-a-wagmi-ui-for-your-contract/"
4040

4141
[functions]
42-
included_files = [
43-
"./src/intl/**/*",
44-
"!./public/**/*",
45-
"!./node_modules/@swc/core-linux-x64-musl/**/*",
46-
"!./node_modules/@swc/core-linux-x64-gnu/**/*",
47-
]
42+
43+
[functions.___netlify-odb-handler]
44+
included_files = [
45+
"./src/intl/**/*",
46+
"!./public/**/*",
47+
"node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/router-context*",
48+
"node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/amp-context*",
49+
"node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/head-manager-context*",
50+
]
51+
52+
[functions.___netlify-handler]
53+
included_files = [
54+
"./src/intl/**/*",
55+
"!./public/**/*",
56+
"node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/router-context*",
57+
"node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/amp-context*",
58+
"node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/head-manager-context*",
59+
]

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"lodash.merge": "^4.6.2",
4242
"lodash.shuffle": "^4.2.0",
4343
"lodash.union": "^4.6.0",
44-
"next": "13.4.8",
44+
"next": "^14.2.3",
4545
"next-i18next": "^14.0.3",
4646
"next-mdx-remote": "^3.0.8",
4747
"next-sitemap": "^4.2.3",
@@ -61,7 +61,6 @@
6161
},
6262
"devDependencies": {
6363
"@chakra-ui/cli": "^2.4.1",
64-
"@chakra-ui/storybook-addon": "5.1.0",
6564
"@netlify/plugin-nextjs": "^4.41.3",
6665
"@storybook/addon-essentials": "7.6.6",
6766
"@storybook/addon-interactions": "7.6.6",
@@ -73,12 +72,12 @@
7372
"@types/decompress": "^4.2.7",
7473
"@types/hast": "^3.0.0",
7574
"@types/node": "^20.4.2",
76-
"@types/react": "^18.2.15",
77-
"@types/react-dom": "^18.2.7",
75+
"@types/react": "18.2.57",
76+
"@types/react-dom": "18.2.19",
7877
"chromatic": "^10.5.0",
7978
"decompress": "^4.2.1",
8079
"eslint": "^8.45.0",
81-
"eslint-config-next": "^13.0.0",
80+
"eslint-config-next": "^14.2.2",
8281
"eslint-config-prettier": "^9.0.0",
8382
"eslint-plugin-simple-import-sort": "^10.0.0",
8483
"eslint-plugin-storybook": "^0.6.15",

public/content/developers/docs/consensus-mechanisms/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,4 @@ _Know of a community resource that helped you? Edit this page and add it!_
8989
- [Proof-of-work](/developers/docs/consensus-mechanisms/pow/)
9090
- [Mining](/developers/docs/consensus-mechanisms/pow/mining/)
9191
- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos/)
92+
- [Proof-of-authority](/developers/docs/consensus-mechanisms/poa/)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
title: Proof-of-authority (PoA)
3+
description: An explanation of the proof-of-authority consensus protocol and its role in blockchain ecosystem.
4+
lang: en
5+
---
6+
7+
**Proof-of-authority (PoA)** is a reputation-based consensus algorithm that is a modified version of [proof-of-stake](/developers/docs/consensus-mechanisms/pos/). It is mostly used by private chains, testnets, and local development networks. PoA is a reputation-based consensus algorithm that requires trusting a set of authorized signers to produce blocks, instead of a stake-based mechanism in PoS.
8+
9+
## Prerequisites {#prerequisites}
10+
11+
To better understand this page, we recommend you first read up on [transactions](/developers/docs/transactions/), [blocks](/developers/docs/blocks/), and [consensus mechanisms](/developers/docs/consensus-mechanisms/).
12+
13+
## What is proof-of-authority (PoA)? {#what-is-poa}
14+
15+
Proof-of-authority is a modified version of **[proof-of-stake](/developers/docs/consensus-mechanisms/pos/) (PoS)** that is a reputation-based consensus algorithm instead of stake-based mechanism in PoS. The term has been introduced for the first time in 2017 by Gavin Wood, and this consensus algorithm has been mostly used by private chains, testnets and local development networks, as it overcomes the need for high quality resources as PoW does, and overcomes the scalability issues with PoS by having small subset of nodes storing the blockchain and producing blocks.
16+
17+
Proof-of-authority requires trusting a set of authorized signers that are set in the [genesis block](/glossary/#genesis-block). In most current implementations, all authorized signers retain equal power and privileges when determining consensus of the chain. The idea behind reputation staking is every authorized validator is well-known to everyone through things like know your customer (KYC), or by having a well-known organization being the only validator—this way if a validator does anything wrong, their identity is known.
18+
19+
There are multiple implementations of PoA, but the standard Ethereum implementation is **clique**, which implements [EIP-225](https://eips.ethereum.org/EIPS/eip-225). Clique is developer-friendly and an easy-to-implement standard, supporting all client syncing types. Other implementations include [IBFT 2.0](https://besu.hyperledger.org/stable/private-networks/concepts/poa) and [Aura](https://openethereum.github.io/Chain-specification).
20+
21+
## How it works {#how-it-works}
22+
23+
In PoA, a set of authorized signers are selected to create new blocks. The signers are selected based on their reputation, and they are the only ones allowed to create new blocks. The signers are selected in a round-robin fashion, and each signer is allowed to create a block in a specific time frame. The block creation time is fixed, and the signers are required to create a block within that time frame.
24+
25+
The reputation in this context is not a quantified thing but rather it is the reputation of well-known corporations like Microsoft and Google, hence the way of selecting the trusted signers is not algorithmic but rather it is the normal human act of _trust_ where an entity let's say for example Microsoft creates a PoA private network between hundreds or thousands of startups and the role itself as the only trusted signer with the possibility of adding other well-known signers like Google in the future, the startups would, without doubt, trust Microsoft to act in an honest manner all the times and use the network. This solves the need to stake in different small/private networks that were built for different purposes to keep them decentralized and functioning, along with the need for miners which consumes a lot of power and resources. Some private networks use the PoA standard as it such as VeChain, and some modify it such as Binance which uses [PoSA](https://academy.binance.com/en/glossary/proof-of-staked-authority-posa) which is a custom modified version of PoA and PoS.
26+
27+
The voting process is done by the signers themselves. Each signer votes for the addition or removal of a signer in their block when they create a new block. The votes are tallied up by the nodes, and the signers are added or removed based on the votes reaching a certain threshold `SIGNER_LIMIT`.
28+
29+
There may be a situation where small forks occur, the difficulty of a block depends on whether the block was signed in turn or out of turn. “In turn” blocks have difficulty 2, and “out of turn” blocks have difficulty 1. In the case of small forks, the chain with most of the signers sealing blocks “in turn” will accumulate the most difficulty and win.
30+
31+
## Attack vectors {#attack-vectors}
32+
33+
### Malicious signers {#malicious-signers}
34+
35+
A malicious user could be added to the list of signers, or a signing key/machine might be compromised. In such a scenario the protocol needs to be able to defend itself against reorganizations and spamming. The proposed solution is that given a list of N authorized signers, any signer may only mint 1 block out of every K. This ensures that damage is limited, and the remainder of the miners can vote out the malicious user.
36+
37+
### Censorship {#censorship-attack}
38+
39+
Another interesting attack vector is if a signer (or group of signers) attempts to censor blocks that vote on removing them from the authorization list. To work around this, the allowed minting frequency of signers is restricted to 1 out of N/2. This ensures that malicious signers need to control at least 51% of signing accounts, at which point they would effectively become the new source-of-truth for the chain.
40+
41+
### Spam {#spam-attack}
42+
43+
Another small attack vector is malicious signers injecting new vote proposals inside every block they mint. Since nodes need to tally up all votes to create the actual list of authorized signers, they must record all votes over time. Without placing a limit on the vote window, this could grow slowly, yet unbounded. The solution is to place a _moving_ window of W blocks after which votes are considered stale. _A reasonable window might be 1-2 epochs._
44+
45+
### Concurrent blocks {#concurrent-blocks}
46+
47+
In a PoA network, When there are N authorized signers, each signer is allowed to mint 1 block out of K, which means that N-K+1 miners are allowed to mint at any given point in time. To prevent these miners from racing for blocks, each signer should add a small random "offset" to the time it releases a new block. Although this process ensures that small forks are rare, occasional forks can still happen, just like mainnet. If a signer is found to be abusing its power and causing chaos, the other signers can vote them out.
48+
49+
If for example there are 10 authorized signers and each signer is allowed to create 1 block out of 20, then at any given time, 11 miners can create blocks. To prevent them from racing to create blocks, each signer adds a small random "offset" to the time they release a new block. This reduces the occurrence of small forks but still allows occasional forks, as seen on the Ethereum Mainnet. If a signer misuses their authority and causes disruptions, they can be voted out of the network.
50+
51+
## Pros and cons {#pros-and-cons}
52+
53+
| Pros | Cons |
54+
| --------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
55+
| Scalable more than other popular mechanisms such PoS and PoW, as it's based on a limited number of block signers | PoA networks typically have a relatively small number of validating nodes. This makes a PoA network more centralized. |
56+
| PoA blockchains are incredibly cheap to run and maintain | Becoming an authorized signer is typically out of reach for an ordinary person, because the blockchain requires entities with established reputation. |
57+
| The transactions are confirmed very quick as it could reach less than 1 second because only limited number of signers are required to validate new blocks | Malicious signers could reorg, double spend, censor transactions in the network, those attacks are mitigated but still possible |
58+
59+
## Further reading {#further-reading}
60+
61+
- [EIP-225](https://eips.ethereum.org/EIPS/eip-225) _Clique standard_
62+
- [Proof of Authority study](https://github.com/cryptoeconomics-study/website/blob/master/docs/sync/2.4-lecture.md) _Cryptoeconomics_
63+
- [What is Proof of Authority](https://forum.openzeppelin.com/t/proof-of-authority/3577) _OpenZeppelin_
64+
- [Proof of Authority Explained](https://academy.binance.com/en/articles/proof-of-authority-explained) _binance_
65+
- [PoA in blockchain](https://medium.com/techskill-brew/proof-of-authority-or-poa-in-blockchain-part-11-blockchain-series-be15b3321cba)
66+
- [Clique explained](https://medium.com/@Destiner/clique-cross-client-proof-of-authority-algorithm-for-ethereum-8b2a135201d)
67+
- [Deprecated PoA, Aura specification](https://openethereum.github.io/Chain-specification)
68+
- [IBFT 2.0, another PoA implementation](https://besu.hyperledger.org/stable/private-networks/concepts/poa)
69+
70+
### More of a visual learner? {#visual-learner}
71+
72+
Watch a visual explanation of proof-of-authority:
73+
74+
<YouTube id="Mj10HSEM5_8" />
75+
76+
## Related topics {#related-topics}
77+
78+
- [Proof-of-work](/developers/docs/consensus-mechanisms/pow/)
79+
- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos/)

0 commit comments

Comments
 (0)