【软件工程与实践】(9)账本初始化的代码分析

2021SC@SDUSC

账本初始化

1.LedgerInitOperation

这个是一个接口,我们可以看到,它定义了账本初始化的设置。

public interface LedgerInitOperation extends Operation{
    
    
	
	@DataField(order=1, refContract=true)
	LedgerInitSetting getInitSetting();
	
}

2.LedgerInitSettings

这也是一个关于账本初始化的接口,这个接口账本初始化的设置

代码定义了账本的种子

@DataField(order = 1, primitiveType = PrimitiveType.BYTES)
	byte[] getLedgerSeed();

这个是共识方的参与列表,列表里面有一系列用户,这个方法同时可以给下面的方法提供相应的用户列表。

@DataField(order = 2, list = true, refContract = true)
	ParticipantNode[] getConsensusParticipants();

这个是密码算法配置

@DataField(order = 3, refContract = true)
	CryptoSetting getCryptoSetting();

代码用共识算法实现Provider

@DataField(order = 4, primitiveType = PrimitiveType.TEXT)
	String getConsensusProvider();

共识算法配置

@DataField(order = 5, primitiveType = PrimitiveType.BYTES)
	Bytes getConsensusSettings();

账本创建事件

@DataField(order = 6, primitiveType = PrimitiveType.INT64)
	long getCreatedTime();

账本结构版本号。

@DataField(order = 7, primitiveType = PrimitiveType.INT64)
	long getLedgerStructureVersion();

LedgerInitProperties

这是一个账本所有信息的类
代码中定义了好几个变量/常量,为了方便我全部写在了注释里面

// 账本种子;
	public static final String LEDGER_SEED = "ledger.seed";

	// 账本名称
	public static final String LEDGER_NAME = "ledger.name";

	// 声明的账本建立时间;
	public static final String CREATED_TIME = "created-time";
	// 创建时间的格式;
	public static final String CREATED_TIME_FORMAT = Global.DEFAULT_TIME_FORMAT;

	// 角色清单;
	public static final String ROLES = "security.roles";
	// 角色的账本权限;用角色名称替代占位符;
	public static final String ROLE_LEDGER_PRIVILEGES_PATTERN = "security.role.%s.ledger-privileges";
	// 角色的交易权限;用角色名称替代占位符;
	public static final String ROLE_TX_PRIVILEGES_PATTERN = "security.role.%s.tx-privileges";

	// 共识参与方的个数,后续以 part.id 分别标识每一个参与方的配置;
	public static final String PART_COUNT = "cons_parti.count";
	// 共识参与方的名称的模式;
	public static final String PART_ID_PATTERN = "cons_parti.%s";
	// 参与方的名称;
	public static final String PART_NAME = "name";
	// 参与方的公钥文件路径;
	public static final String PART_PUBKEY_PATH = "pubkey-path";
	// 参与方的公钥文件路径;
	public static final String PART_PUBKEY = "pubkey";
	// 参与方的角色清单;
	public static final String PART_ROLES = "roles";
	// 参与方的角色权限策略;
	public static final String PART_ROLES_POLICY = "roles-policy";

	// 共识参与方的账本初始服务的主机;
	public static final String PART_INITIALIZER_HOST = "initializer.host";
	// 共识参与方的账本初始服务的端口;
	public static final String PART_INITIALIZER_PORT = "initializer.port";
	// 共识参与方的账本初始服务是否开启安全连接;
	public static final String PART_INITIALIZER_SECURE = "initializer.secure";

	// 共识服务的参数配置;必须;
	public static final String CONSENSUS_CONFIG = "consensus.conf";

	// 共识服务提供者;必须;
	public static final String CONSENSUS_SERVICE_PROVIDER = "consensus.service-provider";

	// 密码服务提供者列表,以英文逗点“,”分隔;必须;
	public static final String CRYPTO_SERVICE_PROVIDERS = "crypto.service-providers";
	// 从存储中加载账本数据时,是否校验哈希;可选;
	public static final String CRYPTO_VRIFY_HASH = "crypto.verify-hash";
	// 哈希算法;
	public static final String CRYPTO_HASH_ALGORITHM = "crypto.hash-algorithm";

这个方法是用来获取共识节点的方法,方法接受一个共识节点,进行判断,如果为空则返回null,如果不为空则返回共识节点的数组。

public ParticipantNode[] getConsensusParticipantNodes() {
    
    
		if (consensusParticipants.isEmpty()) {
    
    
			return null;
		}
		ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipants.size()];
		return consensusParticipants.toArray(participantNodes);
	}

这个方法是用来返回二进制的共识节点信息

public CryptoProperties getCryptoProperties() {
    
    
		return cryptoProperties;
	}

	public void setCryptoProperties(CryptoProperties cryptoProperties) {
    
    
		if (cryptoProperties == null) {
    
    
			cryptoProperties = new CryptoProperties();
		}
		this.cryptoProperties = cryptoProperties;
	}

代码返回事件的参与者,id 从 1 开始; 小于等于#getConsensusParticipantCount()

public ParticipantProperties getConsensusParticipant(int id) {
    
    
		for (ParticipantProperties p : consensusParticipants) {
    
    
			if (p.getId() == id) {
    
    
				return p;
			}
		}
		return null;
	}

前一个私有方法用来获取账本种子,是一个私有的构造器;
第二个方法是用来添加共识的参与者,输入一个共识的参与者,方法会将它加入到列表里面;
第三个是一个私有静态方法,这个方法用户获取参与者的公钥。

private LedgerInitProperties(byte[] ledgerSeed) {
    
    
		this.ledgerSeed = ledgerSeed;
	}

	public void addConsensusParticipant(ParticipantProperties participant) {
    
    
		consensusParticipants.add(participant);
	}

	private static String getKeyOfParticipant(int partId, String partPropKey) {
    
    
		String partAddrStr = String.format(PART_ID_PATTERN, partId);
		return String.format("%s.%s", partAddrStr, partPropKey);
	}

第一个是一个公有的静态方法,这个方法可以读取账本初始的配置信息,然后方法内部调用FileUtil的方法将文本转化成utf8的格式,然后返回配置的信息以及路径;
第二个方法的作用和第一个差不多,不过它的输入流和第一个不同;
第三个方法也是。

public static LedgerInitProperties resolve(String initSettingFile) {
    
    
		Properties props = FileUtils.readProperties(initSettingFile, "UTF-8");
		File realFile = new File(initSettingFile);
		return resolve(realFile.getParentFile().getPath(), props);
	}

	public static LedgerInitProperties resolve(InputStream in) {
    
    
		Properties props = FileUtils.readProperties(in, "UTF-8");
		return resolve(props);
	}

	public static LedgerInitProperties resolve(Properties props) {
    
    
		return resolve(null, props);
	}

从属性表解析账本初始化参数;
baseDirectory基础路径;
属性中涉及文件位置的相对路径以此参数指定的目录为父目录;
要解析的属性表;
由于代码长度原因,我将解析同样写在了代码之中

public static LedgerInitProperties resolve(String baseDirectory, Properties props) {
    
    
		String hexLedgerSeed = PropertiesUtils.getRequiredProperty(props, LEDGER_SEED).replace("-", "");
		byte[] ledgerSeed = HexUtils.decode(hexLedgerSeed);
		LedgerInitProperties initProps = new LedgerInitProperties(ledgerSeed);

这个方法是用来过来解析账本信息,账本名称。

public static LedgerInitProperties resolve(String baseDirectory, Properties props) {
    
    
		String hexLedgerSeed = PropertiesUtils.getRequiredProperty(props, LEDGER_SEED).replace("-", "");
		byte[] ledgerSeed = HexUtils.decode(hexLedgerSeed);
		LedgerInitProperties initProps = new LedgerInitProperties(ledgerSeed);

		// 解析账本信息;
		// 账本名称
		String ledgerName = PropertiesUtils.getRequiredProperty(props, LEDGER_NAME);
		initProps.ledgerName = ledgerName;

		// 创建时间;
		String strCreatedTime = PropertiesUtils.getRequiredProperty(props, CREATED_TIME);
		try {
    
    
			initProps.createdTime = new SimpleDateFormat(CREATED_TIME_FORMAT).parse(strCreatedTime).getTime();
		} catch (ParseException ex) {
    
    
			throw new IllegalArgumentException(ex.getMessage(), ex);
		}

		// 解析角色清单;
		String strRoleNames = PropertiesUtils.getOptionalProperty(props, ROLES);
		String[] roles = StringUtils.splitToArray(strRoleNames, ",");

		Map<String, RoleInitData> rolesInitSettingMap = new TreeMap<String, RoleInitData>();
		// 解析角色权限表;
		for (String role : roles) {
    
    
			String ledgerPrivilegeKey = getKeyOfRoleLedgerPrivilege(role);
			String strLedgerPermissions = PropertiesUtils.getOptionalProperty(props, ledgerPrivilegeKey);
			LedgerPermission[] ledgerPermissions = resolveLedgerPermissions(strLedgerPermissions);

			String txPrivilegeKey = getKeyOfRoleTxPrivilege(role);
			String strTxPermissions = PropertiesUtils.getOptionalProperty(props, txPrivilegeKey);
			TransactionPermission[] txPermissions = resolveTransactionPermissions(strTxPermissions);

			if (ledgerPermissions.length > 0 || txPermissions.length > 0) {
    
    
				RoleInitData rolesSettings = new RoleInitData(role, ledgerPermissions, txPermissions);
				rolesInitSettingMap.put(role, rolesSettings);
			}
		}
		RoleInitData[] rolesInitDatas = rolesInitSettingMap.values()
				.toArray(new RoleInitData[rolesInitSettingMap.size()]);
		initProps.setRoles(rolesInitDatas);

		// 解析共识相关的属性;
		initProps.consensusProvider = PropertiesUtils.getRequiredProperty(props, CONSENSUS_SERVICE_PROVIDER);
		String consensusConfigFilePath = PropertiesUtils.getRequiredProperty(props, CONSENSUS_CONFIG);
		try {
    
    
			initProps.consensusConfig = FileUtils.readPropertiesResouce(consensusConfigFilePath, baseDirectory);
		} catch (FileNotFoundException e) {
    
    
			throw new IllegalArgumentException(
					String.format("Consensus config file[%s] doesn't exist! ", consensusConfigFilePath), e);
		}

		// 解析密码提供者列表;
		String cryptoProviderNames = PropertiesUtils.getProperty(props, CRYPTO_SERVICE_PROVIDERS, true);
		String[] cryptoProviders = cryptoProviderNames.split(CRYPTO_SERVICE_PROVIDERS_SPLITTER);
		for (int i = 0; i < cryptoProviders.length; i++) {
    
    
			cryptoProviders[i] = cryptoProviders[i].trim();
		}
		initProps.cryptoProperties.setProviders(cryptoProviders);
		// 哈希校验选项;
		boolean verifyHash = PropertiesUtils.getBooleanOptional(props, CRYPTO_VRIFY_HASH, false);
		initProps.cryptoProperties.setVerifyHash(verifyHash);
		// 哈希算法;
		String hashAlgorithm = PropertiesUtils.getOptionalProperty(props, CRYPTO_HASH_ALGORITHM);
		initProps.cryptoProperties.setHashAlgorithm(hashAlgorithm);

		// 解析参与方节点列表;
		int partCount = getInt(PropertiesUtils.getRequiredProperty(props, PART_COUNT));
		if (partCount < 0) {
    
    
			throw new IllegalArgumentException(String.format("Property[%s] is negative!", PART_COUNT));
		}
		if (partCount < 4) {
    
    
			throw new IllegalArgumentException(String.format("Property[%s] is less than 4!", PART_COUNT));
		}
		for (int i = 0; i < partCount; i++) {
    
    
			ParticipantProperties parti = new ParticipantProperties();

			parti.setId(i);

			String nameKey = getKeyOfParticipant(i, PART_NAME);
			parti.setName(PropertiesUtils.getRequiredProperty(props, nameKey));

			String pubkeyPathKey = getKeyOfParticipant(i, PART_PUBKEY_PATH);
			String pubkeyPath = PropertiesUtils.getProperty(props, pubkeyPathKey, false);

			String pubkeyKey = getKeyOfParticipant(i, PART_PUBKEY);
			String base58PubKey = PropertiesUtils.getProperty(props, pubkeyKey, false);
			if (base58PubKey != null) {
    
    
				PubKey pubKey = KeyGenUtils.decodePubKey(base58PubKey);
				parti.setPubKey(pubKey);
			} else if (pubkeyPath != null) {
    
    
				PubKey pubKey = KeyGenUtils.readPubKey(pubkeyPath);
				parti.setPubKey(pubKey);
			} else {
    
    
				throw new IllegalArgumentException(
						String.format("Property[%s] and property[%s] are all empty!", pubkeyKey, pubkeyPathKey));
			}

			// 解析参与方的角色权限配置;
			String partiRolesKey = getKeyOfParticipant(i, PART_ROLES);
			String strPartiRoles = PropertiesUtils.getOptionalProperty(props, partiRolesKey);
			String[] partiRoles = StringUtils.splitToArray(strPartiRoles, ",");
			parti.setRoles(partiRoles);

			String partiRolePolicyKey = getKeyOfParticipant(i, PART_ROLES_POLICY);
			String strPartiPolicy = PropertiesUtils.getOptionalProperty(props, partiRolePolicyKey);
			RolesPolicy policy = strPartiPolicy == null ? RolesPolicy.UNION
					: RolesPolicy.valueOf(strPartiPolicy.trim());
			policy = policy == null ? RolesPolicy.UNION : policy;
			parti.setRolesPolicy(policy);

			// 解析参与方的网络配置参数;
			String initializerHostKey = getKeyOfParticipant(i, PART_INITIALIZER_HOST);
			String initializerHost = PropertiesUtils.getRequiredProperty(props, initializerHostKey);

			String initializerPortKey = getKeyOfParticipant(i, PART_INITIALIZER_PORT);
			int initializerPort = getInt(PropertiesUtils.getRequiredProperty(props, initializerPortKey));

			String initializerSecureKey = getKeyOfParticipant(i, PART_INITIALIZER_SECURE);
			boolean initializerSecure = Boolean
					.parseBoolean(PropertiesUtils.getRequiredProperty(props, initializerSecureKey));
			NetworkAddress initializerAddress = new NetworkAddress(initializerHost, initializerPort, initializerSecure);
			parti.setInitializerAddress(initializerAddress);
			parti.setParticipantNodeState(ParticipantNodeState.CONSENSUS);
			initProps.addConsensusParticipant(parti);
		}

		return initProps;
	}

这是一个私有的静态方法,有关于事务性的许可,输入一个事务性许可的string,然后方法调用splitToArray方法把字符串分割开来,然后制成一个列表,如果不为空那么用valueOf的方法获得其值;
如果permission不为空那么将它加入原有的permission;

private static TransactionPermission[] resolveTransactionPermissions(String strTxPermissions) {
    
    
		String[] strPermissions = StringUtils.splitToArray(strTxPermissions, ",");
		List<TransactionPermission> permissions = new ArrayList<TransactionPermission>();
		if (strPermissions != null) {
    
    
			for (String pm : strPermissions) {
    
    
				TransactionPermission permission = TransactionPermission.valueOf(pm);
				if (permission != null) {
    
    
					permissions.add(permission);
				}
			}
		}
		return permissions.toArray(new TransactionPermission[permissions.size()]);
	}

猜你喜欢

转载自blog.csdn.net/weixin_45932150/article/details/121594734