Substrate 基础教程(Tutorials) -- 授权特定节点

article/2025/8/26 11:25:55

五、授权特定节点

在添加可信节点中,您看到了如何使用一组已知的验证器节点构建一个简单的网络。该教程演示了一个简化版的许可网络(permissioned network)。在一个被许可的网络中,只有被授权的节点(authorized nodes)被允许执行特定的网络活动。例如,您可以授予一些节点验证块的权限,授予其他节点传播交易的权限。

具有被授予特定权限的节点的区块链不同于公共(public )或无授权(permissionless )的区块链。在无授权的区块链中,任何人都可以通过在合适的硬件上运行节点软件来加入网络。一般来说,无授权区块链提供了更大的网络去中心化。但是,在某些用例中,创建一个受许可的区块链可能是合适的。例如,一个被许可的区块链将适用于以下类型的项目:

  • 用于私有或联盟网络(private or consortium network),如私人企业或非营利组织。
  • 在高度监管的数据环境中,例如医疗保健、金融或企业对企业分类账。
  • 用于大规模测试预公开的区块链网络(pre-public blockchain )。

本教程演示如何使用节点授权 pallet构建带有Substrate的受许可网络。

5.1 节点授权和所有权

节点授权 pallet 是一个预先构建的 FRAME托盘,使您能够管理网络的一组可配置的节点。每个节点由一个peer identifier (PeerId)标识。每个对等标识符由声明该节点的一个且只有能一个帐户所有者(AccountId)拥有。

有两种方式可以授权一个节点加入网络:

  • 通过将对等标识符添加到链规范文件中的预定义节点列表中,作为链的起源配置的一部分。您必须获得链的治理机制的批准,或者有权访问网络中Sudo pallet 的根帐户才能执行此操作。
  • 通过请求来自特定节点的配对对等(paired peer )连接。您可以使用预定义的节点对等标识符,或者使用每个节点的公钥和私钥生成的对等标识符,在节点之间添加连接。

如下图所示,本教程演示了两种授权方法,其中AliceBob的对等标识符定义在链规范中,其他节点使用节点授权pallet(node authorization pallet)添加。

在这里插入图片描述
请注意,任何用户都可以声称自己是PeerId的所有者。为了防止错误声明,应该在启动节点之前声明节点标识符。启动节点后,它的PeerID对网络可见,任何人都可以随后声明它。

作为节点的所有者,您可以为节点添加和删除连接。例如,您可以操作预定义节点与您的节点之间的连接,或者您的节点与其他非预定义节点之间的连接。不能更改预定义节点的连接。他们总是被允许相互联系。

节点授权(node-authorization)pallet 使用脱链工作器(offchain worker )来配置其节点连接。请确保在启动节点时启用脱链工作器,因为对于非权威节点,默认情况下它是禁用的

5.2 教程的目标

通过完成本教程,您将实现以下目标:

  • 签出并编译节点模板。
  • 将节点授权托盘(node authorization pallet)添加到节点模板运行时。
  • 启动多个节点并授权新节点加入。

5.3 构建节点模板

参考前面文章

5.4 添加节点授权托盘

在使用新托盘之前,必须将有关它的一些信息添加到编译器用于构建运行时二进制文件的配置文件中。

对于Rust程序,您使用Cargo.toml文件定义配置设置和依赖项,这些设置和依赖项决定在生成的二进制文件中编译什么。因为Substrate运行时既编译为包含标准库函数的原生Rust二进制文件,也编译为不包含标准库的WebAssembly (Wasm)二进制文件,即Cargo.toml文件控制两个重要的信息:

  • 作为运行时依赖项导入的托盘,包括要导入的托盘的位置和版本。
  • 在编译本机Rust二进制文件时,每个托盘中应该启用的特性。通过启用每个托盘的标准(std)特性集,您可以将运行时编译为包含函数、类型和原语,否则在构建WebAssembly二进制时就会丢失这些原语。

有关在Cargo.toml 文件中添加依赖项的一般信息,请参阅Cargo文档中的依赖项。有关启用和管理依赖包中的特性的信息,请参阅Cargo文档中的特性。

5.5 添加节点授权依赖项

将节点授权(node-authorization)托盘添加到Substrate运行时:

  1. 打开终端shell并更改到节点模板的根目录。
  2. 在文本编辑器中打开runtime/Cargo.toml配置文件。
  3. 找到[dependencies]部分,并添加pallet-node-authorization crate ,使其对节点模板运行时可用。
[dependencies]
pallet-node-authorization = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" }

这一行将pallet-node-authorization crate 作为依赖项导入,并为板条箱指定以下配置细节:

  • 在编译运行时时,默认情况下不启用托盘特性。
  • crate的版本标识符。
  • 检索pallet-node-authorization crate 的存储库位置。
  • 用来取crate 的分支

请注意,您应该对所有托盘使用相同的分支和版本信息,以确保它们彼此兼容。使用来自不同分支的托盘可能会导致编译器错误。这个示例演示了向Cargo.toml文件添加托盘,如果其他托盘使用branch = "polkadot-v0.9.28"

pallet-node-authorization/std特性添加到要在编译运行时启用的features 列表中。

[features]
default = ['std']
std = [..."pallet-node-authorization/std",    # add this line...
]

此部分指定此运行时要编译的默认特性集是std特性集。当使用std特性集编译运行时,将启用作为依赖项列出的所有托盘中的std特性。有关如何使用标准库将运行时编译为原生Rust二进制文件,以及如何使用no_std属性将运行时编译为WebAssembly二进制文件的更多详细信息,请参见构建过程。

如果您忘记更新Cargo.toml文件中的features 部分,您可能会看到在编译运行时二进制文件时cannot find function错误。

通过运行以下命令检查新的依赖项是否正确解析:

cargo check -p node-template-runtime --release

5.6 添加管理规则

为了在本教程中模拟治理,您可以配置托盘以使用可以使用Sudo托盘调用的EnsureRoot 特权函数。默认情况下,节点模板中包含Sudo托盘,并允许您通过根级管理帐户(root-level administrative account)进行调用。在生产环境中,您将使用更实际的基于治理的检查。

要在运行时启用EnsureRoot 规则:

  1. 打开runtime/src/lib.rs文件。
  2. 在文件中添加如下一行:
use frame_system::EnsureRoot;

5.7 实现Config trait

每个托盘都有一个Rust trait,称为ConfigConfigtrait 用于标识托盘所需的参数和类型。

添加托盘所需的大多数特定于托盘的代码都是使用Config trait实现的。您可以通过参考其Rust文档或该托盘的源代码来查看需要为任何托盘实现的内容。例如,要了解在节点授权托盘中需要为Configtrait 实现什么,可以参考Rust文档中的pallet_node_authorization::Config。

要在运行时中实现node-authorization托盘:

  1. 打开runtime/src/lib.rs文件。
  2. 使用以下代码为托盘添加parameter_types部分:
parameter_types! {pub const MaxWellKnownNodes: u32 = 8;pub const MaxPeerIdLength: u32 = 128;
}
  1. 使用以下代码为托盘的Configtrait添加impl部分:
impl pallet_node_authorization::Config for Runtime {type RuntimeEvent = RuntimeEvent;type MaxWellKnownNodes = MaxWellKnownNodes;type MaxPeerIdLength = MaxPeerIdLength;type AddOrigin = EnsureRoot<AccountId>;type RemoveOrigin = EnsureRoot<AccountId>;type SwapOrigin = EnsureRoot<AccountId>;type ResetOrigin = EnsureRoot<AccountId>;type WeightInfo = ();
}
  1. 使用以下代码行将托盘添加到construct_runtime宏:
construct_runtime!(
pub enum Runtime whereBlock = Block,NodeBlock = opaque::Block,UncheckedExtrinsic = UncheckedExtrinsic{/*** Add This Line ***/NodeAuthorization: pallet_node_authorization::{Pallet, Call, Storage, Event<T>, Config<T>},}
);
  1. 执行以下命令检查配置是否可以编译。
cargo check -p node-template-runtime --release

在这里插入图片描述

为授权节点添加genesis存储

在启动网络以使用节点授权之前,需要进行一些额外的配置来处理对等标识符和帐户标识符。例如,PeerIdbs58格式编码,因此您需要在node/Cargo.toml中为bs58库添加一个新的依赖项。对PeerId进行解码,得到PeerId的bytes。为了简单起见,授权的节点与预定义的帐户相关联。

为授权节点配置genesis存储:

  1. 打开 node/Cargo.toml
  2. 找到[dependencies]部分并将bs58库添加到节点模板中。
[dependencies]
bs58 = { version = "0.4.0" }
  1. 打开 node/src/chain_spec.rs
  2. 使用以下代码为被授权加入网络的节点添加genesis存储:
use sp_core::OpaquePeerId; // A struct wraps Vec<u8> to represent the node `PeerId`.
use node_template_runtime::NodeAuthorizationConfig; // The genesis config that serves the pallet.
  1. 找到为FRAME模块配置初始存储状态的testnet_genesis函数。

在这里插入图片描述

  1. GenesisConfig声明中,添加以下代码块:
 node_authorization: NodeAuthorizationConfig {nodes: vec![(OpaquePeerId(bs58::decode("12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2").into_vec().unwrap()),endowed_accounts[0].clone()),(OpaquePeerId(bs58::decode("12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust").into_vec().unwrap()),endowed_accounts[1].clone()),],},

在这段代码中,NodeAuthorizationConfig包含一个nodes属性,它是一个包含两个元素的元组的向量。元组的第一个元素是OpaquePeerIdbs58::decode操作将人类可读的PeerId(例如,12d3koowbmawcd4pjnjvfv89hwe48nwkrmago8vy3uqeynnhbox2)转换为字节。元组的第二个元素是AccountId,表示该节点的所有者。本例使用预定义的Alice和Bob,在这里被标识为赋值帐户[0]和[1]。

验证节点是否编译成功

cargo build --release

如果没有语法错误,就可以继续了。如果有错误,请按照编译输出中的说明修复它们,然后重新运行cargo构建命令。

5.8 标识要使用的帐户密钥

您已经在genesis存储中配置了与Alice和Bob帐户关联的节点。您可以使用 subkey程序检查与预定义帐户相关联的密钥,并生成和检查您自己的密钥。但是,如果您运行subkey generate-node-key命令,您的节点密钥和对等标识符将随机生成,并且不会与教程中使用的密钥匹配。因为本教程使用预定义帐户和众所周知的节点密钥,所以您可以为每个帐户使用以下密钥。

Alice

Key typeKey value
Node keyc12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a
Peer identifier generated from the node key12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2
Peer identifier decoded to hex0x0024080112201ce5f00ef6e89374afb625f1ae4c1546d31234e87e3c3f51a62b91dd6bfa57df

Bob

Key typeKey value
Node key6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58
Peer identifier generated from the node key12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust
Peer identifier decoded to hex0x002408011220dacde7714d8551f674b8bb4b54239383c76a2b286fa436e93b2b7eb226bf4de7

另外两个开发帐户—charliedave—没有在genesis配置中定义的众所周知的节点键或对等标识符。为了便于演示,您可以对这些帐户使用以下密钥。

Charlie

Key typeKey value
Node keya99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a
Peer identifier generated from the node key12D3KooWPHWFrfaJzxPnqnAYAoRUyAHHKqACmEycGTVmeVhQYuZN
Peer identifier decoded to hex0x002408011220c81bc1d7057a1511eb9496f056f6f53cdfe0e14c8bd5ffca47c70a8d76c1326d

Dave

Key typeKey value
Node keya99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a
Peer identifier generated from the node key12D3KooWPHWFrfaJzxPnqnAYAoRUyAHHKqACmEycGTVmeVhQYuZN
Peer identifier decoded to hex0x002408011220c81bc1d7057a1511eb9496f056f6f53cdfe0e14c8bd5ffca47c70a8d76c1326d

对于本教程,您可以将 node key 复制到文件中,然后使用subkey inspect-node-key来验证CharlieDave的对等标识符。例如,将Charlie的节点密钥保存到名为charlie-node-key的文件中,然后执行如下命令验证peer 标识符

./subkey inspect-node-key --file charlie-node-key

查看Charlie节点的对等体标识符。

12D3KooWJvyP3VJYymTqG7eH4PM5rN4T2agk5cdNCfNymAqwqcvZ

如果您为自己的帐户生成节点密钥,请将节点的对等标识符保存到一个文件中,以便在需要时将其传递给subkey inspect-node-key或其他命令。

5.9 启动网络节点

现在可以使用预定义帐户的节点密钥和对等标识符启动受许可的网络,并授权其他节点加入。

在本教程中,您将启动四个节点。其中三个节点与预定义的帐户相关联,所有这三个节点都被允许创建和验证块。第四个节点是 sub-node,它只被授权在节点所有者批准的情况下从选定的节点读取数据。

启动第一个节点

因为您已经配置了genesis存储为AliceBob使用众所周知的节点键,您可以使用-name alice --validator命令的快捷方式--alice来启动第一个节点。

启动第一个节点:

./target/release/node-template \
--chain=local \
--base-path /tmp/validator1 \
--alice \
--node-key=c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a \
--port 30333 \
--ws-port 9944 \
--unsafe-ws-external \
--unsafe-rpc-external
[root@localhost substrate-node-template]# ./target/release/node-template --chain=local --base-path /tmp/validator1 --alice --node-key=c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a --port 30333 --ws-port 9944 --unsafe-ws-external
2023-03-02 17:40:31 Low open file descriptor limit configured for the process. Current value: 4096, recommended value: 10000.    
2023-03-02 17:40:31 Substrate Node    
2023-03-02 17:40:31 ✌️  version 4.0.0-dev-d79d8cef20b    
2023-03-02 17:40:31 ❤️  by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2023    
2023-03-02 17:40:31 📋 Chain specification: Local Testnet    
2023-03-02 17:40:31 🏷  Node name: Alice    
2023-03-02 17:40:31 👤 Role: AUTHORITY    
2023-03-02 17:40:31 💾 Database: RocksDb at /tmp/validator1/chains/local_testnet/db/full    
2023-03-02 17:40:31 ⛓  Native runtime: node-template-100 (node-template-1.tx1.au1)    
2023-03-02 17:40:32 🔨 Initializing Genesis block/state (state: 0xabe9…794a, header-hash: 0x1280…bbc0)    
2023-03-02 17:40:32 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.    
2023-03-02 17:40:32 Using default protocol ID "sup" because none is configured in the chain specs    
2023-03-02 17:40:32 🏷  Local node identity is: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2    
2023-03-02 17:40:32 💻 Operating system: linux    
2023-03-02 17:40:32 💻 CPU architecture: x86_64    
2023-03-02 17:40:32 💻 Target environment: gnu    
2023-03-02 17:40:32 💻 CPU: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz    
2023-03-02 17:40:32 💻 CPU cores: 2    
2023-03-02 17:40:32 💻 Memory: 1960MB    
2023-03-02 17:40:32 💻 Kernel: 5.4.230-1.el7.elrepo.x86_64    
2023-03-02 17:40:32 💻 Linux distribution: CentOS Linux 7 (Core)    
2023-03-02 17:40:32 💻 Virtual machine: yes    
2023-03-02 17:40:32 📦 Highest known block at #0    
2023-03-02 17:40:32 〽️ Prometheus exporter started at 127.0.0.1:9615    
2023-03-02 17:40:32 Running JSON-RPC HTTP server: addr=127.0.0.1:9933, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-02 17:40:32 Running JSON-RPC WS server: addr=0.0.0.0:9944, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-02 17:40:37 💤 Idle (0 peers), best: #0 (0x1280…bbc0), finalized #0 (0x1280…bbc0), ⬇ 0 ⬆ 0    

在此命令中,使用--node-key选项指定用于安全连接到网络的密钥。该键也在内部用于生成人类可读的PeerId,如上面部分所示。

启动第二个节点

您可以使用-name bob--validator命令的快捷方式--bob来启动第一个节点。

./target/release/node-template \
--chain=local \
--base-path /tmp/validator2 \
--bob \
--node-key=6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58 \
--bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 \
--port 30334 \
--ws-port 9945 \
--unsafe-ws-external
[root@localhost ~]# cd /home/ycp/work_space/rust_dev/substrate/substrate-node-template/
[root@localhost substrate-node-template]# ./target/release/node-template \
> --chain=local \
> --base-path /tmp/validator2 \
> --bob \
> --node-key=6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58 \
> --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 \
> --port 30334 \
> --ws-port 9945
2023-03-03 13:11:36 Low open file descriptor limit configured for the process. Current value: 4096, recommended value: 10000.    
2023-03-03 13:11:36 Substrate Node    
2023-03-03 13:11:36 ✌️  version 4.0.0-dev-d79d8cef20b    
2023-03-03 13:11:36 ❤️  by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2023    
2023-03-03 13:11:36 📋 Chain specification: Local Testnet    
2023-03-03 13:11:36 🏷  Node name: Bob    
2023-03-03 13:11:36 👤 Role: AUTHORITY    
2023-03-03 13:11:36 💾 Database: RocksDb at /tmp/validator2/chains/local_testnet/db/full    
2023-03-03 13:11:36 ⛓  Native runtime: node-template-100 (node-template-1.tx1.au1)    
2023-03-03 13:11:38 🔨 Initializing Genesis block/state (state: 0xabe9…794a, header-hash: 0x1280…bbc0)    
2023-03-03 13:11:38 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.    
2023-03-03 13:11:39 Using default protocol ID "sup" because none is configured in the chain specs    
2023-03-03 13:11:39 🏷  Local node identity is: 12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust    
2023-03-03 13:11:39 💻 Operating system: linux    
2023-03-03 13:11:39 💻 CPU architecture: x86_64    
2023-03-03 13:11:39 💻 Target environment: gnu    
2023-03-03 13:11:39 💻 CPU: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz    
2023-03-03 13:11:39 💻 CPU cores: 2    
2023-03-03 13:11:39 💻 Memory: 1960MB    
2023-03-03 13:11:39 💻 Kernel: 5.4.230-1.el7.elrepo.x86_64    
2023-03-03 13:11:39 💻 Linux distribution: CentOS Linux 7 (Core)    
2023-03-03 13:11:39 💻 Virtual machine: yes    
2023-03-03 13:11:39 📦 Highest known block at #0    
2023-03-03 13:11:39 Running JSON-RPC HTTP server: addr=127.0.0.1:38501, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-03 13:11:39 Running JSON-RPC WS server: addr=127.0.0.1:9945, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-03 13:11:39 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/172.17.0.1/tcp/30333    
2023-03-03 13:11:39 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/192.168.159.128/tcp/30333    
2023-03-03 13:11:39 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/192.168.122.1/tcp/30333    
2023-03-03 13:11:39 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/172.18.0.1/tcp/30333    
2023-03-03 13:11:42 🙌 Starting consensus session on top of parent 0x1280d6cee470b920e522114266a3c6695a25543c01ec95bd72900e4b7f4dbbc0    
2023-03-03 13:11:42 🎁 Prepared block for proposing at 1 (0 ms) [hash: 0x7b7742d7cac5e44872580013037888fd869503a3d726ba69d94edd671093778f; parent_hash: 0x1280…bbc0; extrinsics (1): [0x91c2…3fb0]]    
2023-03-03 13:11:42 🔖 Pre-sealed block for proposal at 1. Hash now 0xf346b19280be500e9678f74c8afaea98f01c3465c31c04861eb3adba61f79f39, previously 0x7b7742d7cac5e44872580013037888fd869503a3d726ba69d94edd671093778f.    
2023-03-03 13:11:42 ✨ Imported #1 (0xf346…9f39)    
2023-03-03 13:11:44 💤 Idle (1 peers), best: #1 (0xf346…9f39), finalized #0 (0x1280…bbc0), ⬇ 1.0kiB/s ⬆ 1.1kiB/s    
2023-03-03 13:11:48 ✨ Imported #2 (0xae84…8b37)    
2023-03-03 13:11:49 💤 Idle (1 peers), best: #2 (0xae84…8b37), finalized #0 (0x1280…bbc0), ⬇ 0.9kiB/s ⬆ 0.8kiB/s    
2023-03-03 13:11:54 🙌 Starting consensus session on top of parent 0xae84b118f5904a97ad6e73eeff186c5491bd509a3dbeb327be71fd611ce78b37    
2023-03-03 13:11:54 🎁 Prepared block for proposing at 3 (0 ms) [hash: 0xd1905fddbad92c08a068c1d4827781b60836a135019e99aed3e59c9215f37ab5; parent_hash: 0xae84…8b37; extrinsics (1): [0x7c68…1dbc]]    

向已知节点列表中添加第三个节点

您可以使用--name charlie命令启动第三个节点。节点授权托盘使用脱链工作器来配置节点连接。因为第三个节点不是一个众所周知的节点,并且它将网络中的第四个节点配置为只读子节点,所以必须包含命令行选项来启用脱链工作器

./target/release/node-template \
--chain=local \
--base-path /tmp/validator3 \
--name charlie  \
--node-key=3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e \
--port 30335 \
--ws-port=9946 \
--offchain-worker always \
--unsafe-ws-external
[root@localhost substrate-node-template]# ./target/release/node-template \
> --chain=local \
> --base-path /tmp/validator3 \
> --name charlie  \
> --node-key=3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e \
> --port 30335 \
> --ws-port=9946 \
> --offchain-worker always \
> --unsafe-ws-external
2023-03-03 13:19:12 Low open file descriptor limit configured for the process. Current value: 4096, recommended value: 10000.    
2023-03-03 13:19:12 Substrate Node    
2023-03-03 13:19:12 ✌️  version 4.0.0-dev-d79d8cef20b    
2023-03-03 13:19:12 ❤️  by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2023    
2023-03-03 13:19:12 📋 Chain specification: Local Testnet    
2023-03-03 13:19:12 🏷  Node name: charlie    
2023-03-03 13:19:12 👤 Role: FULL    
2023-03-03 13:19:12 💾 Database: RocksDb at /tmp/validator3/chains/local_testnet/db/full    
2023-03-03 13:19:12 ⛓  Native runtime: node-template-100 (node-template-1.tx1.au1)    
2023-03-03 13:19:14 🔨 Initializing Genesis block/state (state: 0xabe9…794a, header-hash: 0x1280…bbc0)    
2023-03-03 13:19:14 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.    
2023-03-03 13:19:15 Using default protocol ID "sup" because none is configured in the chain specs    
2023-03-03 13:19:15 🏷  Local node identity is: 12D3KooWJvyP3VJYymTqG7eH4PM5rN4T2agk5cdNCfNymAqwqcvZ    
2023-03-03 13:19:15 💻 Operating system: linux    
2023-03-03 13:19:15 💻 CPU architecture: x86_64    
2023-03-03 13:19:15 💻 Target environment: gnu    
2023-03-03 13:19:15 💻 CPU: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz    
2023-03-03 13:19:15 💻 CPU cores: 2    
2023-03-03 13:19:15 💻 Memory: 1960MB    
2023-03-03 13:19:15 💻 Kernel: 5.4.230-1.el7.elrepo.x86_64    
2023-03-03 13:19:15 💻 Linux distribution: CentOS Linux 7 (Core)    
2023-03-03 13:19:15 💻 Virtual machine: yes    
2023-03-03 13:19:15 📦 Highest known block at #0    
2023-03-03 13:19:15 Running JSON-RPC HTTP server: addr=127.0.0.1:38533, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-03 13:19:15 Running JSON-RPC WS server: addr=0.0.0.0:9946, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-03 13:19:15 discovered: 12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust /ip4/172.18.0.1/tcp/30334    
2023-03-03 13:19:15 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/192.168.159.128/tcp/30333    
2023-03-03 13:19:15 discovered: 12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust /ip4/192.168.159.128/tcp/30334    
2023-03-03 13:19:15 discovered: 12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust /ip4/192.168.122.1/tcp/30334    
2023-03-03 13:19:15 discovered: 12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust /ip4/172.17.0.1/tcp/30334    
2023-03-03 13:19:15 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/172.17.0.1/tcp/30333    
2023-03-03 13:19:15 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/172.18.0.1/tcp/30333    
2023-03-03 13:19:15 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/192.168.122.1/tcp/30333    
2023-03-03 13:19:20 💤 Idle (0 peers), best: #0 (0x1280…bbc0), finalized #0 (0x1280…bbc0), ⬇ 1.2kiB/s ⬆ 1.2kiB/s    
2023-03-03 13:19:25 💤 Idle (0 peers), best: #0 (0x1280…bbc0), finalized #0 (0x1280…bbc0), ⬇ 0.2kiB/s ⬆ 0.2kiB/s    
2023-03-03 13:19:30 💤 Idle (0 peers), best: #0 (0x1280…bbc0), finalized #0 (0x1280…bbc0), ⬇ 0 ⬆ 48 B/s    
2023-03-03 13:19:35 💤 Idle (0 peers), best: #0 (0x1280…bbc0), finalized #0 (0x1280…bbc0), ⬇ 0.2kiB/s ⬆ 90 B/s    
2023-03-03 13:19:40 💤 Idle (0 peers), best: #0 (0x1280…bbc0), finalized #0 (0x1280…bbc0), ⬇ 0 ⬆ 0    

启动此节点后,您应该看到该节点没有连接的peers (no connected peers )。因为这是一个受许可的网络,所以必须显式地授权节点连接。Alice和Bob节点是在chain_spec.rs文件中配置的。所有其他节点必须通过调用Sudo托盘手动添加。

授权第三个节点访问

本教程使用Sudo托盘进行治理。因此,您可以使用Sudo托盘调用节点授权(node-authorization)托盘提供的addWellKnownNode函数来添加第三个节点。为了简单起见,您可以使用Polkadot/Substrate Portal应用程序来访问Sudo托盘。

  1. 在浏览器中打开Polkadot/Substrate Portal。
    在这里插入图片描述

  2. 单击Developer并选择Sudo

  3. 选择nodeAuthorization并选择addWellKnownNode(节点,所有者)。

  4. 在所需的0x前缀之后复制并粘贴Charlie拥有的节点的十六进制编码的对等标识符。

  5. 选择Charlie作为节点所有者。

  6. 单击“提交Sudo”。
    在这里插入图片描述

  7. Authorize transaction中,请注意Alice开发帐户是默认的根管理帐户,并用作此调用的sudo源,然后单击Sign and Submit
    在这里插入图片描述

  8. 单击Network并选择Explorer以查看最近的交易。
    在这里插入图片描述

在将交易包含在块中之后,您应该看到charlie节点连接到alicebob节点,并开始同步块。这三个节点可以使用本地网络默认启用的mDNS发现机制相互查找。还要确保所有本地防火墙都配置为允许mDNS

023-03-08 16:50:06 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 44 B/s ⬆ 65 B/s    
2023-03-08 16:50:11 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 49 B/s ⬆ 52 B/s    
2023-03-08 16:50:16 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 16:50:21 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 16:50:26 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 49 B/s ⬆ 49 B/s    
2023-03-08 16:50:31 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 16:50:36 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 16:50:41 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 94 B/s ⬆ 0.1kiB/s    
2023-03-08 16:50:46 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0.7kiB/s ⬆ 0.7kiB/s    
2023-03-08 16:50:51 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 16:50:56 💤 Idle (2 peers), best: #130 (0x8ae2…0232), finalized #128 (0x2cfe…cb34), ⬇ 8.0kiB/s ⬆ 1.2kiB/s    
2023-03-08 16:51:00 ✨ Imported #131 (0x120b…5074)    
2023-03-08 16:51:01 💤 Idle (2 peers), best: #131 (0x120b…5074), finalized #128 (0x2cfe…cb34), ⬇ 1.5kiB/s ⬆ 1.3kiB/s    
2023-03-08 16:51:06 ✨ Imported #132 (0xba26…8f62)    
2023-03-08 16:51:06 💤 Idle (2 peers), best: #132 (0xba26…8f62), finalized #129 (0x1549…b4ca), ⬇ 1.4kiB/s ⬆ 1.3kiB/s    
2023-03-08 16:51:11 💤 Idle (2 peers), best: #132 (0xba26…8f62), finalized #130 (0x8ae2…0232), ⬇ 1.5kiB/s ⬆ 1.3kiB/s    
2023-03-08 16:51:12 ✨ Imported #133 (0xd475…027e)    
2023-03-08 16:51:16 💤 Idle (2 peers), best: #133 (0xd475…027e), finalized #131 (0x120b…5074), ⬇ 1.4kiB/s ⬆ 1.2kiB/s    
2023-03-08 16:51:18 ✨ Imported #134 (0x66c9…1903)    
2023-03-08 16:51:21 💤 Idle (2 peers), best: #134 (0x66c9…1903), finalized #132 (0xba26…8f62), ⬇ 1.5kiB/s ⬆ 1.4kiB/s    
2023-03-08 16:51:24 ✨ Imported #135 (0x5714…803e)    
2023-03-08 16:51:26 💤 Idle (2 peers), best: #135 (0x5714…803e), finalized #133 (0xd475…027e), ⬇ 1.4kiB/s ⬆ 1.2kiB/s    
2023-03-08 16:51:30 ✨ Imported #136 (0x18a8…d256)    

如果您的节点不在同一个本地网络上,您应该使用命令行选项--no-mdns禁用它。

允许从子节点连接

该网络中的第四个节点不会用作验证器,也不会添加到已知节点列表中。第四个节点由dave用户帐户拥有,但它是charlie节点的子节点。子节点只能通过连接到父节点charlie拥有的节点来访问网络。重要的是要记住,父节点负责它授权连接到网络的任何子节点。如果需要删除或审计子节点,父节点的所有者负责控制访问。

因为这是一个受许可的网络,Charlie必须配置他的节点,以允许来自Dave拥有的节点的连接。您可以使用Polkadot/Substrate Portal应用程序授予此权限。

允许子节点访问网络:

  1. 在浏览器中打开Polkadot/Substrate Portal。
  2. 单击Developer并选择Extrinsics
  3. 选择nodeAuthorization并选择addConnections(node, connections)

在这里插入图片描述

  1. 复制并粘贴Charlie拥有的节点的0x前缀十六进制编码的对等标识符。
  2. 对于连接参数,复制并粘贴Dave拥有的节点的0x前缀十六进制编码的对等标识符,然后单击Submit Transaction
    在这里插入图片描述
  3. 查看交易详细信息,然后单击Sign and Submit

声明子节点

在启动子节点之前,节点所有者应该声明其节点的对等标识符。您可以使用Polkadot/Substrate Portal应用程序提交一个交易来声明dave帐户拥有的节点。

  1. 在浏览器中打开Polkadot/Substrate Portal。
  2. 单击Developer并选择Extrinsics
  3. 选择nodeAuthorization并选择claimNode(node)
  4. 、复制并粘贴Dave拥有的节点的0x前缀十六进制编码的对等标识符,然后单击Submit Transaction
  5. 查看交易详细信息,然后单击Sign and Submit
    在这里插入图片描述

启动子节点

声明节点对等标识符之后,就可以启动子节点了。

./target/release/node-template \
--chain=local \
--base-path /tmp/validator4 \
--name dave \
--node-key=a99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a \
--port 30336 \
--ws-port 9947 \
--offchain-worker always
# ./target/release/node-template \
--chain=local \
--base-path /tmp/validator4 \
--name dave \
--node-key=a99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a \
--port 30336 \
--ws-port 9947 \
--offchain-worker always
2023-03-08 17:15:33 Substrate Node    
2023-03-08 17:15:33 ✌️  version 4.0.0-dev-d79d8cef20b    
2023-03-08 17:15:33 ❤️  by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2023    
2023-03-08 17:15:33 📋 Chain specification: Local Testnet    
2023-03-08 17:15:33 🏷  Node name: dave    
2023-03-08 17:15:33 👤 Role: FULL    
2023-03-08 17:15:33 💾 Database: RocksDb at /tmp/validator4/chains/local_testnet/db/full    
2023-03-08 17:15:33 ⛓  Native runtime: node-template-100 (node-template-1.tx1.au1)    
2023-03-08 17:15:34 🔨 Initializing Genesis block/state (state: 0x3842…5bbd, header-hash: 0xc459…148f)    
2023-03-08 17:15:34 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.    
2023-03-08 17:15:35 Using default protocol ID "sup" because none is configured in the chain specs    
2023-03-08 17:15:35 🏷  Local node identity is: 12D3KooWPHWFrfaJzxPnqnAYAoRUyAHHKqACmEycGTVmeVhQYuZN    
2023-03-08 17:15:35 💻 Operating system: linux    
2023-03-08 17:15:35 💻 CPU architecture: x86_64    
2023-03-08 17:15:35 💻 Target environment: gnu    
2023-03-08 17:15:35 💻 CPU: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz    
2023-03-08 17:15:35 💻 CPU cores: 4    
2023-03-08 17:15:35 💻 Memory: 2945MB    
2023-03-08 17:15:35 💻 Kernel: 5.19.0-35-generic    
2023-03-08 17:15:35 💻 Linux distribution: Ubuntu 22.04.2 LTS    
2023-03-08 17:15:35 💻 Virtual machine: yes    
2023-03-08 17:15:35 📦 Highest known block at #0    
2023-03-08 17:15:35 Running JSON-RPC HTTP server: addr=127.0.0.1:46715, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-08 17:15:35 Running JSON-RPC WS server: addr=127.0.0.1:9947, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]    
2023-03-08 17:15:35 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/192.168.159.132/tcp/30333    
2023-03-08 17:15:35 discovered: 12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust /ip4/192.168.159.132/tcp/30334    
2023-03-08 17:15:40 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 1.1kiB/s ⬆ 1.0kiB/s    
2023-03-08 17:15:45 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0.2kiB/s ⬆ 0.2kiB/s    
2023-03-08 17:15:50 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 17:15:55 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0.2kiB/s ⬆ 0.1kiB/s    
2023-03-08 17:16:00 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 17:16:05 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 50 B/s ⬆ 65 B/s    
2023-03-08 17:16:10 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0.2kiB/s ⬆ 0.1kiB/s    
2023-03-08 17:16:15 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 17:16:20 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 17:16:25 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 54 B/s ⬆ 49 B/s    
2023-03-08 17:16:30 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 17:16:35 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    

允许连接到子节点

现在有了一个有四个节点的网络。但是,要允许子节点参与,必须将其配置为允许来自Charlie拥有的父节点的连接。这些步骤类似于前面允许从Dave拥有的节点进行连接所执行的步骤。

允许连接到子节点:

  1. 在浏览器中打开Polkadot/Substrate Portal。
  2. 单击Developer并选择Extrinsics
  3. 选择nodeAuthorization并选择addConnections(node, connections)
  4. 复制并粘贴Dave拥有的节点的0x前缀十六进制编码的对等标识符。
  5. 对于连接参数,复制并粘贴Charlie拥有的节点的0x前缀十六进制编码的对等标识符,然后单击Submit Transaction
    在这里插入图片描述

您现在应该看到子节点只有一个peer(属于charlie的节点),并且正在从链中同步区块。如果子节点没有立即连接到对等节点,请尝试停止并重新启动子节点。

2023-03-08 17:20:45 discovered: 12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust /ip4/192.168.159.132/tcp/30334    
2023-03-08 17:20:45 discovered: 12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 /ip4/192.168.159.132/tcp/30333    
2023-03-08 17:20:50 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 1.1kiB/s ⬆ 1.0kiB/s    
2023-03-08 17:20:55 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0.2kiB/s ⬆ 0.2kiB/s    
2023-03-08 17:21:00 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 17:21:05 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0.3kiB/s ⬆ 0.2kiB/s    
2023-03-08 17:21:10 💤 Idle (0 peers), best: #0 (0xc459…148f), finalized #0 (0xc459…148f), ⬇ 0 ⬆ 0    
2023-03-08 17:21:10 discovered: 12D3KooWJvyP3VJYymTqG7eH4PM5rN4T2agk5cdNCfNymAqwqcvZ /ip4/192.168.159.132/tcp/30335/ws    
2023-03-08 17:21:15 💤 Idle (1 peers), best: #161 (0xc285…c0d6), finalized #0 (0xc459…148f), ⬇ 8.7kiB/s ⬆ 1.3kiB/s    
2023-03-08 17:21:20 💤 Idle (1 peers), best: #161 (0xc285…c0d6), finalized #159 (0x16b6…e2bd), ⬇ 0.4kiB/s ⬆ 0.3kiB/s    
2023-03-08 17:21:25 💤 Idle (1 peers), best: #161 (0xc285…c0d6), finalized #159 (0x16b6…e2bd), ⬇ 0 ⬆ 0    

5.10 提交交易所需的密钥

您应该注意到,任何帐户都可以用来签署和提交影响其他节点行为的交易。然而,要签署并提交一个影响你不拥有的节点的交易:

  • 交易必须引用链数据(chain data)。
  • 您必须在密钥存储库中拥有具有所需来源的帐户的签名密钥。

在本教程中,所有节点都可以访问开发帐户签名密钥。因此,您能够签署和提交影响任何连接节点的交易,使用帐户代表Charlie或Dave行事。如果您正在为现实世界的应用程序构建一个受许可的网络,那么节点操作员很可能只能访问他们自己的节点密钥,并且节点所有者帐户将被要求签署和提交影响节点的交易,而节点所有者帐户拥有签名密钥的控制权。


http://chatgpt.dhexx.cn/article/623BXw3S.shtml

相关文章

Substrate常见问题

目录标题 1. Rust nightly not installed, please install it!2. Rust WASM toolchain not installed, please install it!3. use pallet::*出错4. failed to load manifest for workspace member5. error: failed to run custom build command for node-template-runtime v4.0…

什么是 Substrate

如果你关注了 Polkadot 项目&#xff0c;可能会多次看到「Substrate」这个词。 它是 Polkadot 项目的重要组成部分&#xff0c;但有关它的信息非常少。 白皮书或黄皮书里找不到&#xff0c; 至少没有专门的介绍「Substrate」。 从较高的层面来看&#xff0c;Substrate 是一个可…

Substrate之旅3:Substrate是什么

Substrate 是从Polkadot 孵化出来的项目。它是一个用来搭建区块链的通用框架&#xff0c;具有以下特点&#xff1a; 可扩展。模块化。开源。 Substrate的框架与组件 框架 其中&#xff1a; P2P: libp2p网络协议&#xff0c;Substrate基于该协议实现了一个不带任何假设的&…

Substrate 基础 -- 教程(Tutorials)

官网 github DOC 面向未来的区块链框架 Substrate 使开发人员能够快速、轻松地构建适合任何用例的未来 证明区块链(future proof blockchains)。 Substrate 文档包括区块链构建器&#xff08;blockchain builders&#xff09;和parachain 项目团队的概念、过程和参考信息。…

【Android 逆向】substrate 框架 ( substrate 简介 | substrate 相关文档资料 )

文章目录 一、substrate 简介二、substrate 相关文档资料 一、substrate 简介 substrate 官网 : http://www.cydiasubstrate.com substrate 框架 是 Cydia 下的逆向工具 , 该框架是开源的 ; substrate 配合对应的 so 动态库 和 头文件 , 可以在 Android / iOS 平台中独立运行 …

ios tableView那些事(三)给tableView添加些图片

感觉光有数据的tableView很丑&#xff0c;那么我们就来美化下吧&#xff0c;加一些图片 #import <UIKit/UIKit.h> /*tableview 一定要用到这两个delegate UITableViewDataSource,UITableViewDelegate */ interface ViewController :UIViewController <UITableViewDa…

QT的TableView实现多级表头

QT的TableView实现多级表头 最近项目需要支持多级表头&#xff0c;QT本身不支持。可重写QHeaderView表头实现。 demo如下&#xff1a; FSItemDelegate.h #pragma once/* 自定义委托类 */ #include <QItemDelegate> #include <QSpinBox> #include <QDoubleSpin…

QML类型:TableView

一、描述 TableView 显示从内置 QML 类型&#xff08;如 ListModel 和 XmlListModel&#xff09;创建的模型中的数据&#xff0c;这些模型仅填充 TableView 中的第一列。要创建具有多列的模型&#xff0c;请使用 TableModel 或继承 QAbstractItemModel 的 C 模型。 TableView…

QML TableView表格使用示例

前言 QML中实现表格可以使用多种方式&#xff0c;比如直接使用ListView&#xff0c;定义每一行delegate&#xff0c;或者自定义Rectangle&#xff0c;放到Flipable中组合使用。Qt Quick Control1中 从5.1版本开始就提供了表格控件&#xff0c;但是感觉不怎么好用&#xff0c;在…

Qt TableView的简单使用

软件环境&#xff1a; ubuntu -------------------------------------------------------------------------------------------------------- 最终效果图&#xff1a; --------------------------------------------------------------------------------------------------…

PyQt5 TableView组件

一、话不多说&#xff0c;先看图 本次要实现的是主窗口内添加widget组件&#xff0c;widget内设置成垂直盒布局&#xff0c;然后在布局中添加tableView、PushButton组件 二、看main函数 if __name__ __main__:app QApplication(sys.argv)# 现在这创建 主窗口 &#xff08;不然…

优雅的开发TableView

前言 UITableView&#xff08;UITableViewController&#xff09;是iOS开发使用频率最高的一个组件。 不管是使用UITableView还是还是UITableViewController&#xff0c;在开发的时候&#xff0c;我们都需要实现两个协议&#xff1a; UITableViewControllerDataSourceUITabl…

JavaFX控件——TableView

在JavaFX 应用中对创建表格最重要的是TableView, TableColumn和TableCell这三个类。 你可以通过实现数据模型&#xff08;data model&#xff09; 和 实现 单元格工厂(cell factory) 来填充表格。 表格类提供了表格列嵌入式的排序能力和必要时调整列宽度的功能。 下面开始学…

ios开发:多个Section的TableView

开发多个Section的tableView。 首先应该考虑到数据源该如何得到 我们这里可以通过两种方式:第一种是读取plist文件。第二种是通过代码进行数据存储以及读取。 多个Section需要的数据源是一个字典&#xff0c;字典里的内容是一个数组。在plist文件中可以这样去创建 在.h文件中…

tableview概述

转自&#xff1a;http://www.cnblogs.com/smileEvday/archive/2012/06/28/tableView.html                 下面分9个方面进行介绍&#xff1a; 一、UITableView概述 UITableView继承自UIScrollView&#xff0c;可以表现为Plain和Grouped两种风格&#xff0c;分…

ios tableView那些事(一)创建一个简单的tableView

工作也有半年多了&#xff01;几乎每个项目中的会用到tableview这个神奇而好用的控件&#xff0c;在学习和工作中都会看别人的博客&#xff01;对我有很大的帮助&#xff0c;就如同站在巨人的肩膀上的感觉吧 哈哈&#xff01;于是决定重新开始写博客&#xff0c;希望能帮助像我…

JavaFX TableView和ListView的点击事件

项目场景&#xff1a; 最近在用JavaFX做一个简易的商城界面&#xff0c;大概想实现这样的功能&#xff1a; 左边显示用户的最近五个购买的产品 使用ListView 点击ListView的项目会定位到相应的tablerow位置 方便用户快速查找中间显示所有可用产品 使用TableView 双击tablerow…

JavaFX【TableView使用详解】

目录 概述 组件 Student ObservableList TableView setCellValueFactory() TableColumn 1. Callback 2. PropertyValueFactory 增加到末行 1、tableView.getItems().add(Student s) 2、list.add(Student s) 删除指定行 1、tableView.getItems().remove(int i) 2、…

QT中TableView数据展示

QT中TableView数据展示 最近在学习QT,大量数据从数据库取出放入QT界面中展示&#xff0c;这时用到了tableView&#xff0c;一些简单的使用分享给大家。 创建数据模型 QStandardItemModel *modelnew QStandardItemModel(); QStandardItemModel是Qt库中的一个类&#xff0c;它…

JAVAFX的TableView基本用法

JAVAFX中的表格显示主要使用TableView 与TableView相关的类: TableColumn TableRow TableCell TablePosition TableViewFocusModel TableViewSelectionModel JavaFX TableView例子: import javafx.application.Application; import javafx.scene.Scene; import javafx.scene…